AWSTemplateFormatVersion: "2010-09-09" # Transform: AWS::Serverless-2016-10-31 Description: | Resources to perform IaC Organization Formation Parameters: BranchName: Type: String Default: main OrgAccessRoleName: Type: String CodeInitBucketName: Type: String Resources: ArtifactsS3Bucket: Metadata: cfn_nag: rules_to_suppress: - id: W35 reason: "S3 Bucket logging configurration is not relevant in this usecase" - id: W51 reason: "S3 bucket policy not relevant for this usecase" Type: AWS::S3::Bucket Properties: BucketName: !Sub orgformation-artifacts-${AWS::AccountId}-${AWS::Region} VersioningConfiguration: Status: Enabled PublicAccessBlockConfiguration: BlockPublicAcls: True BlockPublicPolicy: True IgnorePublicAcls: True RestrictPublicBuckets: True BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 ################# Custom resource management S3 Bucket EmptyS3BucketOnDeletionLambdaExecutionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyName: LoggingPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: - arn:aws:s3:::* - arn:aws:s3:::*/* - PolicyName: S3Policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - s3:List* - s3:GetObjectVersion - s3:DeleteObject - s3:DeleteObjectVersion Resource: - arn:aws:s3:::* - arn:aws:s3:::*/* EmptyS3BucketOnDeletionLambdaFunction: Metadata: cfn_nag: rules_to_suppress: - id: W89 reason: "Lambda functions deployed inside a VPC is not relevant for this use case" Type: "AWS::Lambda::Function" Properties: ReservedConcurrentExecutions: 1 Code: ZipFile: | import cfnresponse import boto3 def handler(event, context): print(event) print('boto version ' + boto3.__version__) # Globals responseData = {} ResponseStatus = cfnresponse.SUCCESS s3bucketName = event['ResourceProperties']['s3bucketName'] if event['RequestType'] == 'Create': responseData['Message'] = "Resource creation successful!" elif event['RequestType'] == 'Update': responseData['Message'] = "Resource update successful!" elif event['RequestType'] == 'Delete': # Need to empty the S3 bucket before it is deleted s3 = boto3.resource('s3') bucket = s3.Bucket(s3bucketName) bucket.object_versions.delete() responseData['Message'] = "Resource deletion successful!" cfnresponse.send(event, context, ResponseStatus, responseData) Handler: index.handler Runtime: python3.7 Role: !GetAtt EmptyS3BucketOnDeletionLambdaExecutionRole.Arn EmptyArtifactsS3BucketOnDeletionCustomResource: Type: Custom::CustomResource Properties: ServiceToken: !GetAtt EmptyS3BucketOnDeletionLambdaFunction.Arn s3bucketName: !Ref ArtifactsS3Bucket ################# Code Commit Repository for Organisation configuration OrganisationConfigurationCodeCommit: Type: AWS::CodeCommit::Repository Properties: RepositoryDescription: Repository used to store the organisation configuration RepositoryName: !Sub organisation-configuration-${AWS::AccountId} Code: BranchName: !Ref BranchName S3: Bucket: !Ref CodeInitBucketName Key: source.zip ################### Roles OrgAccessRole: Metadata: cfn_nag: rules_to_suppress: - id: W28 reason: "Resource found with an explicit name, this disallows updates that require replacement of this resource is intended" - id: W43 reason: "This roles is the AWS Organization for to assume admin role across all organization account. this is an administrator role." Type: AWS::IAM::Role Properties: RoleName: !Ref OrgAccessRoleName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: AWS: !Ref AWS::AccountId Action: - sts:AssumeRole Path: "/" ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess OrgFormationCodePipelineRole: Metadata: cfn_nag: rules_to_suppress: - id: W11 reason: "All policies are defined by service statement and used at the master level to manage the whole AWS Organization" - id: W28 reason: "Resource found with an explicit name, this disallows updates that require replacement of this resource is intended" Type: AWS::IAM::Role Properties: RoleName: orgformationcodepipelinerole AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - codepipeline.amazonaws.com Action: - "sts:AssumeRole" Path: / Policies: - PolicyName: orgformationcodepipelinerole-policy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - codecommit:Get* - codecommit:List* - codecommit:UploadArchive - codebuild:StartBuild - codebuild:BatchGetBuilds - logs:CreateLogStream - s3:GetObject - s3:ListBucket Resource: "*" - Effect: Allow Action: - s3:PutObject Resource: - !Sub arn:aws:s3:::orgformation-artifacts-${AWS::AccountId}-${AWS::Region}/* - !Sub arn:aws:s3:::orgformation-artifacts-${AWS::AccountId}-${AWS::Region} OrgFormationCodeBuildRole: Metadata: cfn_nag: rules_to_suppress: - id: W11 reason: "All policies are defined by service statemant and used at the master level to manage the whole AWS Organization" - id: W28 reason: "Resource found with an explicit name, this disallows updates that require replacement of this resource is intended" Type: AWS::IAM::Role Properties: RoleName: orgformationcodebuildrole AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - codebuild.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: orgformationcodebuildrole-policy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Resource: "*" Action: - codecommit:BatchGetRepositories - codecommit:Get* # - codecommit:GitPull - codecommit:Git* - codecommit:List* - codecommit:CancelUploadArchive - codecommit:UploadArchive - Effect: Allow Resource: "*" Action: - codebuild:StartBuild - Effect: Allow Resource: "*" Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - Effect: Allow Resource: "*" Action: - iam:ListUsers - iam:ListGroups - iam:ListAccountAliases - iam:DeleteAccountAlias - iam:CreateAccountAlias - iam:GetRole - Effect: Allow Resource: "*" Action: - organizations:AcceptHandshake - organizations:AttachPolicy - organizations:CancelHandshake - organizations:CloseAccount - organizations:CreateAccount - organizations:CreateGovCloudAccount - organizations:CreateOrganization - organizations:CreateOrganizationalUnit - organizations:CreatePolicy - organizations:DeclineHandshake - organizations:DeleteOrganization - organizations:DeleteOrganizationalUnit - organizations:DeletePolicy - organizations:DeregisterDelegatedAdministrator - organizations:DescribeAccount - organizations:DescribeCreateAccountStatus - organizations:DescribeEffectivePolicy - organizations:DescribeHandshake - organizations:DescribeOrganization - organizations:DescribeOrganizationalUnit - organizations:DescribePolicy - organizations:DetachPolicy - organizations:DisableAWSServiceAccess - organizations:DisablePolicyType - organizations:EnableAWSServiceAccess - organizations:EnableAllFeatures - organizations:EnablePolicyType - organizations:InviteAccountToOrganization - organizations:LeaveOrganization - organizations:ListAWSServiceAccessForOrganization - organizations:ListAccounts - organizations:ListAccountsForParent - organizations:root - organizations:ListChildren - organizations:ListCreateAccountStatus - organizations:ListDelegatedAdministrators - organizations:ListDelegatedServicesForAccount - organizations:ListHandshakesForAccount - organizations:ListHandshakesForOrganization - organizations:ListOrganizationalUnitsForParent - organizations:ListParents - organizations:ListPolicies - organizations:ListPoliciesForTarget - organizations:ListRoots - organizations:ListTagsForResource - organizations:ListTargetsForPolicy - organizations:MoveAccount - organizations:RegisterDelegatedAdministrator - organizations:RemoveAccountFromOrganization - organizations:TagResource - organizations:UntagResource - organizations:UpdateOrganizationalUnit - organizations:UpdatePolicy - Effect: Allow Resource: "*" Action: - s3:GetObject - s3:ListBucket - Effect: Allow Resource: "*" Action: - sts:AssumeRole - states:SendTaskSuccess - states:SendTaskFailure - Effect: Allow Action: - s3:PutObject Resource: - !Sub arn:aws:s3:::orgformation-artifacts-${AWS::AccountId}-${AWS::Region}/* - !Sub arn:aws:s3:::orgformation-artifacts-${AWS::AccountId}-${AWS::Region} - Effect: Allow Resource: "*" Action: - cloudformation:DescribeStacks - cloudformation:CreateStack - cloudformation:UpdateStack - cloudformation:DeleteStack - cloudformation:DescribeChangeSet - cloudformation:CreateChangeSet - cloudformation:DeleteChangeSet - cloudformation:GetTemplateSummary ################### Roles ##################### Code Build Projects (Linux) OrgFormationCodeBuildProject: Metadata: cfn_nag: rules_to_suppress: - id: W32 reason: "CodeBuild project with specified EncryptionKey value is not relevant in this use case" Type: AWS::CodeBuild::Project Properties: Name: orgformationcodebuildproject Description: Deploy organisation configuration ServiceRole: !GetAtt OrgFormationCodeBuildRole.Arn Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 EnvironmentVariables: - Name: OrgAccessRole Value: !Ref OrgAccessRole - Name: BranchName Value: !Ref BranchName - Name: ArtifactsS3Bucket Value: !Ref ArtifactsS3Bucket - Name: OrganisationConfigurationCodeCommitName Value: !GetAtt OrganisationConfigurationCodeCommit.Name Source: Type: CODEPIPELINE BuildSpec: | version: 0.2 phases: install: runtime-versions: python: 3.8 commands: - | echo "install ..." echo "BranchName: $BranchName" echo "ArtifactsS3Bucket: $ArtifactsS3Bucket" echo "CODEBUILD_SRC_DIR: $CODEBUILD_SRC_DIR" echo "Current path: $(pwd)" echo "OrgAccessRole: $OrgAccessRole" echo "OrganisationConfigurationCodeCommitName: $OrganisationConfigurationCodeCommitName" ACCOUNT_ID=$(aws sts get-caller-identity | jq -c -r .Account) echo "ACCOUNT_ID: $ACCOUNT_ID" echo 'check git version' git --version echo 'update PIP' pip install --upgrade pip pre_build: commands: - echo "pre build ..." - | echo "install aws-organizations-tool" pip install -e ./ orgtool --version orgtool --help - bash ./automation/autoupdate.sh build: commands: - | echo "build ..." cd $CODEBUILD_SRC_DIR - bash ./automation/build.sh post_build: commands: - echo "post build ..." ##################### Code Build Projects (Linux) ############### Pipeline OrgFormationCodePipeline: Type: AWS::CodePipeline::Pipeline Properties: RestartExecutionOnUpdate: false Name: orgformationcodepipeline RoleArn: !GetAtt OrgFormationCodePipelineRole.Arn ArtifactStore: Type: S3 Location: !Ref ArtifactsS3Bucket Stages: - Name: Source Actions: - Name: Source ActionTypeId: Category: Source Owner: AWS Version: 1 Provider: CodeCommit OutputArtifacts: - Name: SourceArtifact Configuration: OutputArtifactFormat: CODEBUILD_CLONE_REF BranchName: !Ref BranchName RepositoryName: !GetAtt OrganisationConfigurationCodeCommit.Name PollForSourceChanges: true RunOrder: 1 - Name: Deploy Actions: - Name: Deploy ActionTypeId: Category: Build Provider: CodeBuild Owner: AWS Version: 1 InputArtifacts: - Name: SourceArtifact OutputArtifacts: - Name: DeployArtifact Configuration: ProjectName: !Ref OrgFormationCodeBuildProject RunOrder: 1 ############# Pipeline Outputs: OutputStackName: Description: Created stack name Value: !Ref AWS::StackName