Sviluppo remoto su AWS: da Cloud9 a VS Code
20 Novembre 2024 - 2 min. read
Alessio Gandini
Cloud-native Development Line Manager
{ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyUnEncryptedObjectUploads", "Effect": "Deny", "Principal": "*", "Action": "s3:PutObject", "Resource": "<CodePipeline Bucket ARN>/*", "Condition": { "StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" } } }, { "Sid": "DenyInsecureConnections", "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": "<CodePipeline Bucket ARN>/*", "Condition": { "Bool": { "aws:SecureTransport": "false" } } }, { "Sid": "crossaccount", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<Account Master ID>:role/<Cross Account Source Role>" }, "Action": "s3:*", "Resource": [ "<CodePipeline Bucket ARN>", "<CodePipeline Bucket ARN>/*", "<CodePipeline Bucket ARN>/**" ] } ] }Questo tipo di policy consente l’accesso al bucket al ruolo Cross Account Source Role e impedisce l’upload di file non criptati nel bucket S3. Al posto di <Cross Account Source Role> nella policy va inserito il nome che si desidera usare per il Cross Account Source Role.Dopo aver creato la chiave ed il bucket è il momento di creare i due ruoli CodePipeline Role e Cross Account Source Role rispettivamente nell’ Account Target e nell’Account Master. Ognuno dei 2 ruoli avrà tre policy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "codecommit:BatchGet*", "codecommit:Get*", "codecommit:List*", "codecommit:Describe*", "codecommit:Post*", "codecommit:Merge*", "codecommit:Test*", "codecommit:Update*", "codecommit:UploadArchive", "codecommit:GitPull" ], "Resource": [ "arn:aws:codecommit:eu-west-1:<Account Master ID>:*" ] }, { "Effect": "Allow", "Action": "codecommit:ListRepositories", "Resource": "*" } ] }
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "kms:DescribeKey", "kms:GenerateDataKey*", "kms:Encrypt", "kms:ReEncrypt*", "kms:Decrypt" ], "Resource": [ "<CodePipeline KMS Key ARN>" ] } ] }
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Example", "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "<CodePipeline Bucket ARN>/*", "<CodePipeline Bucket ARN>/**" ] } ] }
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "<Cross Account Source Role ARN>" } }
{ "Statement": [ { "Action": [ "s3:GetObject", "s3:GetObjectVersion", "s3:GetBucketVersioning" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "s3:PutObject" ], "Resource": [ "arn:aws:s3:::codepipeline*", "arn:aws:s3:::elasticbeanstalk*" ], "Effect": "Allow" }, { "Action": [ "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", "codecommit:GetUploadArchiveStatus", "codecommit:UploadArchive" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "codedeploy:CreateDeployment", "codedeploy:GetApplicationRevision", "codedeploy:GetDeployment", "codedeploy:GetDeploymentConfig", "codedeploy:RegisterApplicationRevision" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "elasticbeanstalk:*", "ec2:*", "elasticloadbalancing:*", "autoscaling:*", "cloudwatch:*", "s3:*", "sns:*", "cloudformation:*", "rds:*", "sqs:*", "ecs:*", "iam:PassRole" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "lambda:InvokeFunction", "lambda:ListFunctions" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "opsworks:CreateDeployment", "opsworks:DescribeApps", "opsworks:DescribeCommands", "opsworks:DescribeDeployments", "opsworks:DescribeInstances", "opsworks:DescribeStacks", "opsworks:UpdateApp", "opsworks:UpdateStack" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "cloudformation:CreateStack", "cloudformation:DeleteStack", "cloudformation:DescribeStacks", "cloudformation:UpdateStack", "cloudformation:CreateChangeSet", "cloudformation:DeleteChangeSet", "cloudformation:DescribeChangeSet", "cloudformation:ExecuteChangeSet", "cloudformation:SetStackPolicy", "cloudformation:ValidateTemplate", "iam:PassRole" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "codebuild:BatchGetBuilds", "codebuild:StartBuild" ], "Resource": "*", "Effect": "Allow" }, { "Effect": "Allow", "Action": [ "devicefarm:ListProjects", "devicefarm:ListDevicePools", "devicefarm:GetRun", "devicefarm:GetUpload", "devicefarm:CreateUpload", "devicefarm:ScheduleRun" ], "Resource": "*" } ], "Version": "2012-10-17" }
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Example", "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "<CodePipeline Bucket ARN>/*", "<CodePipeline Bucket ARN>/**" ] } ] }A questo punto siamo pronti per creare la pipeline usando i comandi dell’AWS CLI. Per prima cosa creiamo un file JSON contenente i parametri per la pipeline:
{ "pipeline": { "roleArn": "<CodePipeline Role ARN>", "stages": [ { "name": "Source", "actions": [ { "inputArtifacts": [], "name": "Source", "roleArn": "<Cross Account Source Role ARN>", "actionTypeId": { "category": "Source", "owner": "AWS", "version": "1", "provider": "CodeCommit" }, "outputArtifacts": [ { "name": "CodeBundle" } ], "configuration": { "PollForSourceChanges": "false", "BranchName": "BranchName", "RepositoryName": "RepositoryName" }, "runOrder": 1 } ] }, { "name": "Build", "actions": [ { "inputArtifacts": [ { "name": "CodeBundle" } ], "name": "CodeBuild", "actionTypeId": { "category": "Build", "owner": "AWS", "version": "1", "provider": "CodeBuild" }, "outputArtifacts": [ { "name": "BuildBundle" } ], "configuration": { "ProjectName": "ProjectName" }, "runOrder": 1 } ] } ], "artifactStore": { "type": "S3", "location": "<CodePipeline Bucket Name>", "encryptionKey": { "id": "<CodePipeline KMS Key ARN>", "type": "KMS" } }, "name": "Pipeline Name", "version": 1 } }Una volta creato il file è possibile usarlo per generare la pipeline tramite la AWS CLI:
aws codepipeline create-pipeline --cli-input-json file://pipeline.json
Fatto questo la nostra pipeline è finalmente pronta! Manca solo un ultimo tocco: far sì che la pipeline venga triggerata in modo automatico ogni volta che uno sviluppatore esegue il push su CodeCommit. Per implementare questo sistema di triggering automatico è necessario creare una CloudWatch event rule sull’Account Master, che viene attivata nel momento in cui si esegue un commit; la regola ha come Target l’Event Bus dell’Account Target. In figura è riportato un esempio di configurazione per questa Rule.Sarà quindi necessario aggiungere un permesso all’event bus dell’account target per far sì che l’Account Master possa scrivere i messaggi nell'account Target. Per fare ciò, è sufficiente aggiungere la permission all’account ID del master dalla dashboard di CloudWatch - Event Buses nell’account target. Infine, sempre nell’Account Target, è necessario creare una seconda CloudWatch Rule, triggerata dallo stesso evento usato per la Rule dell'account master, che avvia la pipeline usando il ruolo CloudWatch Events Role. Questo ruolo dovrà semplicemente avere una policy che gli consenta di avviare l’esecuzione delle pipeline:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "codepipeline:StartPipelineExecution" ], "Resource": [ "<Pipeline ARN>" ] } ] }Una volta aggiunto quest’ultimo componente, la pipeline verrà triggerata in modo automatico ogni volta che uno sviluppatore esegue un commit sul CodeCommit nell’account master.In questo articolo vi abbiamo presentato un metodo innovativo per creare pipeline cross-account, che semplifica notevolmente la gestione dei deploy per progetti suddivisi su più account AWS.Se siete interessati a questa soluzione, o avete domande e suggerimenti, non esitate a contattarci, saremo felici di aiutarvi!