General

Return values of !Ref and !GetAtt are not consistent

Depending upon the used resource, !Ref and !GetAtt do return the Name property, as well as the Arn:

Service !Ref !GetAtt
AWS::ECS::Cluster Name Arn
AWS::ECS::Service Arn Name
AWS::ECS::TaskDefinition Arn none

A full list can be found in the !Ref and !GetAtt cheatsheet.

Stacks

Export a list as output and import the list in another stack.

If you need to export a list of resource identifiers, e.g. all subnets of a VPC, as an output in one stack, you can join the subnets:

# environment-stack.yaml
Resources:
# ....
Outputs:
  AllSubnets:
    Description: All subnets
    Value: !Join
        - ','
        - !GetAtt [ MyVpc, Subnets ]
    Export:
        Name: !Sub "${AWS::StackName}-AllSubnets"

In your other stack, you can then import the output with the following definition:

# other-stack.yaml
Parameters:
  EnvironmentStackName:
    Description: "Name of the stack containing VPC, subnets etc."
    Type: String
    Default: "environment

Resources:
  MyCodeBuildProject:
    Type: AWS::CodeBuild::Project
      VpcConfig:
        Subnets: 
          Fn::Split:
            - ","
            - Fn::ImportValue:
                !Sub "${EnvironmentStackName}-AllSubnets"

Exporting the first entry of a list and referencing it

If you just need the first entry of a list, e.g. the first subnet, you can use the following definition:

# environment-stack.yaml
Resources:
# ....
Outputs:
  FirstSubnet:
    Description: First subnet
    Value:  !Select [0, !GetAtt [MyVpc, Subnets]]
    Export:
        Name: !Sub "${AWS::StackName}-FirstSubnet"

It can then be referenced in the other stack with

# other-stack.yaml
Resources:
  MyLambda:
    Type: AWS::Lambda::Function
    Properties:
      VpcConfig:
        SubnetIds:
          - !ImportValue
            'Fn::Sub': '${EnvironmentStackName}-FirstSubnet'

CodeBuild and CodePipeline

Pushing a Docker image into ECR with CodeBuild

If you are using CodeBuild to push a Docker image into ECR, you have set the PrivilegedMode setting to true. Otherwise, you'll receive the message Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running?

Resources:
  MyBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: "my-project"
      Environment:
        # We need the PrivilegedMode, otherwise the Docker daemon would not be accessible to pull and push the images
        PrivilegedMode: true

In addition to that, you need the correct permissions for the CodeBuild service role. If you don't have the permissions, the docker daemon might hang during pulling or pushing the image.

Resources:
  MyRepository:
    Type: AWS::ECR::Repository
    Properties:
      ImageTagMutability: IMMUTABLE 
      RepositoryName: "my-docker-image"

  MyBuildProject:
    Type: AWS::CodeBuild::Project
      ServiceRole: !GetAtt [MyCodeBuildRole, Arn]

  MyCodeBuildRole:
    Type: AWS::IAM::Role
    Properties:
      Policies:
      - PolicyDocument:
          Statement:
          # Allow CodePipeline to update the ECRs
          - Action:
            - ecr:GetDownloadUrlForLayer
            - ecr:BatchGetImage
            - ecr:CompleteLayerUpload
            - ecr:DescribeImages
            - ecr:DescribeRepositories
            - ecr:UploadLayerPart
            - ecr:ListImages
            - ecr:InitiateLayerUpload
            - ecr:BatchCheckLayerAvailability
            - ecr:PutImage
            Effect: Allow
            Resource:
              Fn::Join:
              - ""
              - - !Sub 'arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository'
                - "/my-docker-image"
                - "/*"

"Insufficient permissions. The provided role does not have sufficient permissions to access ECS"

The error occurs during a CodePipeline build when executing an ECS deployment action. The role of the CodePipeline must allow the permission iam:PassRole in its PolicyDocument:

Resources:
  # region CodeBuild
  CodePipelineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
      # ....
      Path: /
      Policies:
      - PolicyDocument:
          Statement:
          - Action:
            - iam:PassRole
            Effect: Allow
            Resource: '*'

Lambda

The provided execution role does not have permissions to call DescribeNetworkInterfaces on EC2

The error The provided execution role does not have permissions to call DescribeNetworkInterfaces on EC2 occurs, if your Lambda's service is attached to a VPC and is missing the required ec2:* permissions.

Resources:
  MyLambda:
    Type: AWS::Lambda::Function
    Properties:
      Role: !GetAtt [ MyLambdaRole, Arn ]

  MyLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action:
          - sts:AssumeRole
          Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
      Policies:
      - PolicyDocument:
          Statement:
          - Action:
            - ec2:CreateNetworkInterface
            - ec2:DeleteNetworkInterface
            - ec2:DescribeNetworkInterfaces
            Resource: '*'
            Effect: Allow
          Version: '2012-10-17'