When do I need to have CAPABILITY_NAMED_IAM

13,621

Solution 1

When are CAPABILITY_IAM/CAPABILITY_NAMED_IAM Required

According to CloudFormation CreateStack Parameters, one of these is required when your Template includes any of the following resource types:

AWS::IAM::AccessKey
AWS::IAM::Group
AWS::IAM::InstanceProfile
AWS::IAM::Policy
AWS::IAM::Role
AWS::IAM::User
AWS::IAM::UserToGroupAddition 

When to use CAPABILITY_NAMED_IAM instead of CAPABILITY_IAM

When any of your IAM resources have a custom name, such as a RoleName then CAPABILITY_NAMED_IAM is required.

Why are these required?

The Capabilities are there to ensure you realize that you're creating IAM resources, that these will modify the permissions on your account, and that you have reviewed these resources and their permissions as necessary.

Solution 2

You've added a resource of type AWS::IAM::Role to your resources section. This tells CloudFormation to create an IAM Role. In order to create IAM resources, you need to supply CAPABILITY_IAM or CAPABILITY_NAMED_IAM. It's an acknowledgement from you to CloudFormation that you understand that you are creating resources that can affect permissions in your AWS account.

Note on use of CAPABILITY_NAMED_IAM vs CAPABILITY_IAM:

  1. If you have IAM resources with custom names, you must specify CAPABILITY_NAMED_IAM.
  2. Otherwise, if you have IAM resources, you can specify either capability.
Share:
13,621
Jiew Meng
Author by

Jiew Meng

Web Developer & Computer Science Student Tools of Trade: PHP, Symfony MVC, Doctrine ORM, HTML, CSS, jQuery/JS Looking at Python/Google App Engine, C#/WPF/Entity Framework I hope to develop usable web applications like Wunderlist, SpringPad in the future

Updated on June 07, 2022

Comments

  • Jiew Meng
    Jiew Meng almost 2 years

    I was editing my CloudFormation templates and suddenly AWS tells me I need CAPABILITY_NAMED_IAM. I am curious as to which change triggers this?

    What is a named IAM resource?

    Before I already "name" my resources like

    RoleName: !Sub '${PipelineName}-codebuild'
    

    I am not asked to add this capability, I think until I add

    Parameters:
      AppName:
        Type: String
        Description: Prefix for resources
    
    Resources:
      LambdaRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Ref AppName
    

    To my SAM application template. But arent they the "same" except one uses !Ref? Or maybe some other change triggered this?

    For reference, my CodePipeline stack

    AWSTemplateFormatVersion : '2010-09-09'
    Description: 'Skynet stack for CodePipeline'
    
    Parameters:
      PipelineName:
        Type: String
        Description: Pipeline Name (Lower case only, since S3 bucket names can only have lowercase)
        Default: skynet-pipeline
      GitHubOwner:
        Type: String
        Description: GitHub Owner
        Default: 2359media
      GitHubRepo:
        Type: String
        Description: GitHub Repo
        Default: 'skynet'
      GitHubBranch:
        Type: String
        Description: GitHub Branch
        Default: master
      GitHubToken:
        Type: String
        Description: GitHub Token
        NoEcho: true
    
    Resources:
      Pipeline:
        Type: AWS::CodePipeline::Pipeline
        Properties:
          Name: !Ref PipelineName
          RoleArn: !GetAtt [PipelineRole, Arn]
          ArtifactStore:
            Location: !Ref PipelineArtifactStore
            Type: S3
          DisableInboundStageTransitions: []
          Stages:
            - Name: GitHubSource
              Actions:
              - Name: Source
                ActionTypeId:
                  Category: Source
                  Owner: ThirdParty
                  Version: 1
                  Provider: GitHub
                Configuration:
                  Owner: !Ref GitHubOwner
                  Repo: !Ref GitHubRepo
                  Branch: !Ref GitHubBranch
                  OAuthToken: !Ref GitHubToken
                OutputArtifacts:
                  - Name: SourceCode
            - Name: Build
              Actions:
              - Name: Lambda
                InputArtifacts:
                  - Name: SourceCode
                OutputArtifacts:
                  - Name: LambdaPackage
                ActionTypeId:
                  Category: Build
                  Owner: AWS
                  Version: 1
                  Provider: CodeBuild
                Configuration:
                  ProjectName: !Ref CodeBuildLambda
            - Name: CreateChangeSet
              Actions:
              - Name: Lambda
                InputArtifacts:
                  - Name: LambdaPackage
                OutputArtifacts:
                  - Name: LambdaDeployment
                ActionTypeId:
                  Category: Deploy
                  Owner: AWS
                  Version: 1
                  Provider: CloudFormation
                Configuration:
                  ActionMode: CHANGE_SET_REPLACE
                  ChangeSetName: !Sub
                    - '${PipelineName}-lambda'
                    - {PipelineName: !Ref PipelineName}
                  RoleArn: !GetAtt [CloudFormationRole, Arn]
                  StackName: !Sub
                    - '${PipelineName}-lambda'
                    - {PipelineName: !Ref PipelineName}
                  TemplatePath: 'LambdaPackage::SkynetLambdaPackaged.yml'
                  Capabilities: CAPABILITY_NAMED_IAM
                  ParameterOverrides: !Sub '{"AppName": "${PipelineName}-lambda"}'
            - Name: ExecuteChangeSet
              Actions:
              - Name: Lambda
                ActionTypeId:
                  Category: Deploy
                  Owner: AWS
                  Version: 1
                  Provider: CloudFormation
                Configuration:
                  ActionMode: CHANGE_SET_EXECUTE
                  ChangeSetName: !Sub
                    - '${PipelineName}-lambda'
                    - {PipelineName: !Ref PipelineName}
                  StackName: !Sub
                    - '${PipelineName}-lambda'
                    - {PipelineName: !Ref PipelineName}
    
      CodeBuildLambda:
        Type: AWS::CodeBuild::Project
        Properties:
          Name: !Sub '${PipelineName}-lambda'
          Artifacts:
            Type: CODEPIPELINE
          Environment:
            ComputeType: BUILD_GENERAL1_SMALL
            Image: aws/codebuild/nodejs:7.0.0
            Type: LINUX_CONTAINER
            EnvironmentVariables:
              - Name: S3_BUCKET
                Value: !Ref PipelineArtifactStore
          ServiceRole: !Ref CodeBuildRole
          Source:
            BuildSpec: 'lambda/buildspec.yml'
            Type: CODEPIPELINE
    
      PipelineArtifactStore:
        Type: AWS::S3::Bucket
        Properties:
          BucketName: !Sub '${PipelineName}-artifacts'
          VersioningConfiguration:
            Status: Enabled
    
      CodeBuildRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Sub '${PipelineName}-codebuild'
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
              Effect: Allow
              Principal:
                Service: codebuild.amazonaws.com
              Action: sts:AssumeRole
          Policies:
            - PolicyName: !Sub '${PipelineName}-codebuild'
              PolicyDocument:
                Version: '2012-10-17'
                Statement:
                  - Effect: Allow
                    Resource: 'arn:aws:logs:*:*:*'
                    Action:
                    - 'logs:CreateLogGroup'
                    - 'logs:CreateLogStream'
                    - 'logs:PutLogEvents'
                  - Effect: Allow
                    Resource:
                      - !Sub 'arn:aws:s3:::codepipeline-${AWS::Region}-*/*'
                      - !Sub
                        - '${PipelineArtifactStoreArn}/*'
                        - {PipelineArtifactStoreArn: !GetAtt [PipelineArtifactStore, Arn]}
                    Action:
                      - 's3:GetObject'
                      - 's3:GetObjectVersion'
                      - 's3:PutObject'
    
      CloudFormationRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Sub '${PipelineName}-cloudformation'
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Principal:
                Service: cloudformation.amazonaws.com
              Action:
              - sts:AssumeRole
          ManagedPolicyArns:
            - 'arn:aws:iam::aws:policy/AWSLambdaExecute'
          Policies:
            - PolicyName: !Sub '${PipelineName}-cloudformation'
              PolicyDocument:
                Version: '2012-10-17'
                Statement:
                  - Effect: Allow
                    Resource: '*'
                    Action:
                    - 's3:GetObject'
                    - 's3:GetObjectVersion'
                    - 's3:GetBucketVersioning'
                  - Effect: Allow
                    Resource: 'arn:aws:s3:::codepipeline*'
                    Action:
                    - 's3:PutObject'
                  - Effect: Allow
                    Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:*'
                    Action:
                    - 'lambda:*'
                  - Effect: Allow
                    Resource: !Sub 'arn:aws:apigateway:${AWS::Region}::*'
                    Action:
                    - 'apigateway:*'
                  - Effect: Allow
                    Resource: '*'
                    Action:
                    - 'lambda:CreateEventSourceMapping'
                    - 'lambda:DeleteEventSourceMapping'
                    - 'lambda:GetEventSourceMapping'
                  - Effect: Allow
                    Resource: '*'
                    Action:
                    - 'iam:GetRole'
                    - 'iam:CreateRole'
                    - 'iam:DeleteRole'
                    - 'iam:PassRole'
                    - 'iam:AttachRolePolicy'
                    - 'iam:DetachRolePolicy'
                    - 'iam:DeleteRolePolicy'
                    - 'iam:PutRolePolicy'
                  - Effect: Allow
                    Resource: '*'
                    Action:
                    - 'iam:PassRole'
                  - Effect: Allow
                    Resource: !Sub 'arn:aws:cloudformation:${AWS::Region}:aws:transform/Serverless-2016-10-31'
                    Action:
                    - 'cloudformation:CreateChangeSet'
    
      PipelineRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Sub '${PipelineName}-pipeline'
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Action: ['sts:AssumeRole']
              Effect: Allow
              Principal:
                Service: [codepipeline.amazonaws.com]
          Path: /
          Policies:
            - PolicyName: SkynetPipeline
              PolicyDocument:
                Version: '2012-10-17'
                Statement:
                  - Action:
                    - 's3:GetObject'
                    - 's3:GetObjectVersion'
                    - 's3:GetBucketVersioning'
                    Effect: 'Allow'
                    Resource: '*'
                  - Action:
                    - 's3:PutObject'
                    Effect: 'Allow'
                    Resource:
                    - !GetAtt [PipelineArtifactStore, Arn]
                  - Action:
                    - 'codecommit:CancelUploadArchive'
                    - 'codecommit:GetBranch'
                    - 'codecommit:GetCommit'
                    - 'codecommit:GetUploadArchiveStatus'
                    - 'codecommit:UploadArchive'
                    Effect: 'Allow'
                    Resource: '*'
                  - Action:
                    - 'codedeploy:CreateDeployment'
                    - 'codedeploy:GetApplicationRevision'
                    - 'codedeploy:GetDeployment'
                    - 'codedeploy:GetDeploymentConfig'
                    - 'codedeploy:RegisterApplicationRevision'
                    Effect: 'Allow'
                    Resource: '*'
                  - Action:
                    - 'elasticbeanstalk:*'
                    - 'ec2:*'
                    - 'elasticloadbalancing:*'
                    - 'autoscaling:*'
                    - 'cloudwatch:*'
                    - 's3:*'
                    - 'sns:*'
                    - 'cloudformation:*'
                    - 'rds:*'
                    - 'sqs:*'
                    - 'ecs:*'
                    - 'iam:PassRole'
                    Effect: 'Allow'
                    Resource: '*'
                  - Action:
                    - 'lambda:InvokeFunction'
                    - 'lambda:ListFunctions'
                    Effect: 'Allow'
                    Resource: '*'
                  - Action:
                    - 'opsworks:CreateDeployment'
                    - 'opsworks:DescribeApps'
                    - 'opsworks:DescribeCommands'
                    - 'opsworks:DescribeDeployments'
                    - 'opsworks:DescribeInstances'
                    - 'opsworks:DescribeStacks'
                    - 'opsworks:UpdateApp'
                    - 'opsworks:UpdateStack'
                    Effect: 'Allow'
                    Resource: '*'
                  - Action:
                    - 'cloudformation:CreateStack'
                    - 'cloudformation:DeleteStack'
                    - 'cloudformation:DescribeStacks'
                    - 'cloudformation:UpdateStack'
                    - 'cloudformation:CreateChangeSet'
                    - 'cloudformation:DeleteChangeSet'
                    - 'cloudformation:DescribeChangeSet'
                    - 'cloudformation:ExecuteChangeSet'
                    - 'cloudformation:SetStackPolicy'
                    - 'cloudformation:ValidateTemplate'
                    - 'iam:PassRole'
                    Effect: 'Allow'
                    Resource: '*'
                  - Action:
                    - 'codebuild:BatchGetBuilds'
                    - 'codebuild:StartBuild'
                    Effect: 'Allow'
                    Resource: '*'
    

    The part of SAM stack (sam.yml) changed recently

    AWSTemplateFormatVersion : '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: 'Skynet. AWS Management Assistant'
    Parameters:
      AppName:
        Type: String
        Description: Prefix for resources
    
    Resources:
      LambdaRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Ref AppName
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
              - apigateway.amazonaws.com
          Action:
          - sts:AssumeRole
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonEC2FullAccess'
        - 'arn:aws:iam::aws:policy/AWSLambdaFullAccess'
        - 'arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess'
        - 'arn:aws:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess'
        - 'arn:aws:iam::aws:policy/CloudWatchLogsFullAccess'
    
  • Jiew Meng
    Jiew Meng over 6 years
    As long as I am naming my IAM resources I need the named IAM capability correct?
  • Jamie Starke
    Jamie Starke over 6 years
    Yes, as long as the CloudFormation Stack has an IAM Resource that is named.
  • PureW
    PureW over 2 years
    This doesn't answer the question of when to use which of CAPABILITY_IAM vs CAPABILITY_NAMED_IAM
  • jarmod
    jarmod over 2 years
    @PureW Good point, have added clarification.