Answers: <p>It turns out I was doing it wrong due to me being new to CloudFormation.</p>
  <p>For anyone else looking into how to attach both managed and inline policies to a user at the moment of user creation, this is how I do it which <em>incidentally</em> is pretty well documented by the AWS folks:</p>
  <pre class="lang-yaml prettyprint-override"><code>## =================== VERSION ===================
  AWSTemplateFormatVersion: '2010-09-09'
  
  ## =================== DESCRIPTION ===================
  Description: &gt;-
    Creates an IAM User if none is present, optionally manage to which IAM group(s) the user belongs to
    Optionally embed AWS managed policies, customer managed policies and inline policies in the user
  
  ## =================== METADATA ===================
  Metadata: 
    AWS::CloudFormation::Interface: 
      ParameterGroups: 
        -
          Label:
            default: Set a one-time password 
          Parameters:
            - paramOneTimePassword
      ParameterLabels:
        paramOneTimePassword:
          default: ' '
  
  ## =================== PARAMETERS ===================
  Parameters:
    paramOneTimePassword:
      Description: The user will have to pick a new password upon first sign in
      Type: String    
      NoEcho: 'true' # mask the parameter value as asterisks (*****) to prevent it from being displayed in the console, CLI, or API
      ConstraintDescription: Password must be between 8 and 32 characters, start with lowercase or uppercase letter, and can be alphanumeric with the following special characters !@#$%&amp;
  
  ## =================== MAPPINGS ===================
  Mappings:
    mapUserData:
      UserName:
        AWS: testuser
        Real: 'Test User'
      Groups:
        Group: BackendDev
      Tags:
        product: testProduct
    mapManagedPolicies:
      CustomerManagedPolicies: 
        ARN: None
  
  ## =================== CONDITIONS ===================
  Conditions:
    hasManagedPolicy:
      !Not [!Equals [!FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], 'None'] ]
   
  ## =================== RESOURCES ===================
  Resources:
    # myInlinePolicyForChangeOwnPassword:
    #   Type: 'AWS::IAM::Policy'
    #   Properties:
    myUser:
      Type: 'AWS::IAM::User'
      Properties:
        UserName: !FindInMap [mapUserData, UserName, AWS]
        LoginProfile:
          Password: !Ref paramOneTimePassword 
          PasswordResetRequired: true 
        ManagedPolicyArns: # list of ARNs of IAM managed policies that you want to attach to the user
          - !If [ hasManagedPolicy, !FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], !Ref &quot;AWS::NoValue&quot; ]
        Policies:
          - PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Sid: ViewAccountPasswordRequirements
                  Action: 'iam:GetAccountPasswordPolicy'
                  Resource: &quot;*&quot;
                - Effect: Allow
                  Sid: ChangeOwnPassword
                  Action:
                    - 'iam:GetUser'
                    - 'iam:ChangePassword'
                  Resource: !Join ['', [arn:aws:iam::*:user/,!FindInMap [mapUserData, UserName, AWS]]]
            PolicyName: IAM-ChangeOwnPassword
        Groups:
          - !FindInMap [mapUserData, Groups, Group]
        Tags:
          - Key: name
            Value: !FindInMap [mapUserData, UserName, Real]
          - Key: product
            Value: !FindInMap [mapUserData, Tags, product]
  
  ## =================== OUTPUT ===================
  Outputs:
    outputArn:
      Description: User ARN
      Value: !GetAtt myUser.Arn
    outputName:
      Description: User name
      Value: !Ref myUser
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2021-07-19T20:37:06.423Z
Answers: 2021-07-19T20:37:06.423Z
Answers: solr
Body: <p>I'm working on a template that allows to create a user, tag it, and add it to any groups, add any roles, managed policies and in-line policies if needed:</p>
  <pre class="lang-yaml prettyprint-override"><code>## =================== VERSION ===================
  AWSTemplateFormatVersion: '2010-09-09'
  
  ## =================== DESCRIPTION ===================
  Description: &gt;-
    Creates an IAM User if none is present, optionally manage to which IAM group(s) the user belongs to
    Optionally embed AWS managed policies, customer managed policies and inline policies in the user
  
  ## =================== METADATA ===================
  Metadata: 
    AWS::CloudFormation::Interface: 
      ParameterGroups: 
        -
          Label:
            default: Set a one-time password 
          Parameters:
            - paramOneTimePassword
      ParameterLabels:
        paramOneTimePassword:
          default: ' '
  
  ## =================== PARAMETERS ===================
  Parameters:
    paramOneTimePassword:
      Description: The user will have to pick a new password upon first sign in
      Type: String    
      NoEcho: 'true' # mask the parameter value as asterisks (*****) to prevent it from being displayed in the console, CLI, or API
      ConstraintDescription: Password must be between 8 and 32 characters, start with lowercase or uppercase letter, and can be alphanumeric with the following special characters !@#$%&amp;
  
  ## =================== MAPPINGS ===================
  Mappings:
    mapUserData:
      UserName:
        AWS: testuser
        Real: 'Test User'
      Groups:
        Group: BackendDev
      Tags:
        product: testProduct
    mapManagedPolicies:
      CustomerManagedPolicies: 
        ARN: None
  
  ## =================== CONDITIONS ===================
  Conditions:
    hasManagedPolicy:
      !Not [!Equals [!FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], 'None'] ]
   
  ## =================== RESOURCES ===================
  Resources:
    myInlinePolicyForChangeOwnPassword:
      Type: 'AWS::IAM::Policy'
      Properties:
        PolicyName: IAM-ChangeOwnPassword
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Sid: ViewAccountPasswordRequirements
              Action: 'iam:GetAccountPasswordPolicy'
              Resource: &quot;*&quot;
            - Effect: Allow
              Sid: ChangeOwnPassword
              Action:
                - 'iam:GetUser'
                - 'iam:ChangePassword'
              Resource: !Join ['', [arn:aws:iam::*:user/,!FindInMap [mapUserData, UserName, AWS]]]
        Users:
          - !FindInMap [mapUserData, UserName, AWS]
    myUser:
      Type: 'AWS::IAM::User'
      Properties:
        UserName: !FindInMap [mapUserData, UserName, AWS]
        LoginProfile:
          Password: !Ref paramOneTimePassword 
          PasswordResetRequired: true 
        Groups:
          - !FindInMap [mapUserData, Groups, Group]
        ManagedPolicyArns: # list of ARNs of IAM managed policies that you want to attach to the user
          - !If [ hasManagedPolicy, !FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], !Ref &quot;AWS::NoValue&quot; ]
        Tags:
          - Key: name
            Value: !FindInMap [mapUserData, UserName, Real]
          - Key: product
            Value: !FindInMap [mapUserData, Tags, product]
    WaitCondition:
      Type: AWS::CloudFormation::WaitCondition
      DependsOn: myUser
      Properties:
        # Handle: !Ref WaitHandle
        Timeout: 120
        Count: 1
  
  ## =================== OUTPUT ===================
  Outputs:
    outputArn:
      Description: User ARN
      Value: !GetAtt myUser.Arn
    outputName:
      Description: User name
      Value: !Ref myUser
  </code></pre>
  <p>Thing is that there's a race condition between the moment the user creation is triggered, and the moment CF tries to create/attach the in-line policy to the user: if the user haven't finished creating, the stack deployment will fail.</p>
  <p>I read about using <code>WaitCondition</code> but I'm not really sure how to employ it here with IAM resources. I'd greatly appreciate any feedback that can point me into the right direction.</p>
  <p>Thanks</p>
  
Tags: <aws-cloudformation>
Title: How to add a wait condition when creating IAM entities
UserDisplayName: solr
ThreadText: # How to add a wait condition when creating IAM entities
  
  (Asked by: username_0 on 2021-07-19)
  
  I'm working on a template that allows to create a user, tag it, and add it to any groups, add any roles, managed policies and in-line policies if needed:
  
  ```yaml
  ## =================== VERSION ===================
  AWSTemplateFormatVersion: '2010-09-09'
  
  ## =================== DESCRIPTION ===================
  Description: >-
    Creates an IAM User if none is present, optionally manage to which IAM group(s) the user belongs to
    Optionally embed AWS managed policies, customer managed policies and inline policies in the user
  
  ## =================== METADATA ===================
  Metadata: 
    AWS::CloudFormation::Interface: 
      ParameterGroups: 
        -
          Label:
            default: Set a one-time password 
          Parameters:
            - paramOneTimePassword
      ParameterLabels:
        paramOneTimePassword:
          default: ' '
  
  ## =================== PARAMETERS ===================
  Parameters:
    paramOneTimePassword:
      Description: The user will have to pick a new password upon first sign in
      Type: String    
      NoEcho: 'true' # mask the parameter value as asterisks (*****) to prevent it from being displayed in the console, CLI, or API
      ConstraintDescription: Password must be between 8 and 32 characters, start with lowercase or uppercase letter, and can be alphanumeric with the following special characters !@#$%&
  
  ## =================== MAPPINGS ===================
  Mappings:
    mapUserData:
      UserName:
        AWS: testuser
        Real: 'Test User'
      Groups:
        Group: BackendDev
      Tags:
        product: testProduct
    mapManagedPolicies:
      CustomerManagedPolicies: 
        ARN: None
  
  ## =================== CONDITIONS ===================
  Conditions:
    hasManagedPolicy:
      !Not [!Equals [!FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], 'None'] ]
   
  ## =================== RESOURCES ===================
  Resources:
    myInlinePolicyForChangeOwnPassword:
      Type: 'AWS::IAM::Policy'
      Properties:
        PolicyName: IAM-ChangeOwnPassword
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Sid: ViewAccountPasswordRequirements
              Action: 'iam:GetAccountPasswordPolicy'
              Resource: "*"
            - Effect: Allow
              Sid: ChangeOwnPassword
              Action:
                - 'iam:GetUser'
                - 'iam:ChangePassword'
              Resource: !Join ['', [arn:aws:iam::*:user/,!FindInMap [mapUserData, UserName, AWS]]]
        Users:
          - !FindInMap [mapUserData, UserName, AWS]
    myUser:
      Type: 'AWS::IAM::User'
      Properties:
        UserName: !FindInMap [mapUserData, UserName, AWS]
        LoginProfile:
          Password: !Ref paramOneTimePassword 
          PasswordResetRequired: true 
        Groups:
          - !FindInMap [mapUserData, Groups, Group]
        ManagedPolicyArns: # list of ARNs of IAM managed policies that you want to attach to the user
          - !If [ hasManagedPolicy, !FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], !Ref "AWS::NoValue" ]
        Tags:
          - Key: name
            Value: !FindInMap [mapUserData, UserName, Real]
          - Key: product
            Value: !FindInMap [mapUserData, Tags, product]
    WaitCondition:
      Type: AWS::CloudFormation::WaitCondition
      DependsOn: myUser
      Properties:
        # Handle: !Ref WaitHandle
        Timeout: 120
        Count: 1
  
  ## =================== OUTPUT ===================
  Outputs:
    outputArn:
      Description: User ARN
      Value: !GetAtt myUser.Arn
    outputName:
      Description: User name
      Value: !Ref myUser
  
  ```
  
  Thing is that there's a race condition between the moment the user creation is triggered, and the moment CF tries to create/attach the in-line policy to the user: if the user haven't finished creating, the stack deployment will fail.
  
  I read about using `WaitCondition` but I'm not really sure how to employ it here with IAM resources. I'd greatly appreciate any feedback that can point me into the right direction.
  
  Thanks
  
  **Tags:** aws-cloudformation
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_0 on 2021-07-19. Score: 1
  
  It turns out I was doing it wrong due to me being new to CloudFormation.
  
  For anyone else looking into how to attach both managed and inline policies to a user at the moment of user creation, this is how I do it which *incidentally* is pretty well documented by the AWS folks:
  
  ```yaml
  ## =================== VERSION ===================
  AWSTemplateFormatVersion: '2010-09-09'
  
  ## =================== DESCRIPTION ===================
  Description: >-
    Creates an IAM User if none is present, optionally manage to which IAM group(s) the user belongs to
    Optionally embed AWS managed policies, customer managed policies and inline policies in the user
  
  ## =================== METADATA ===================
  Metadata: 
    AWS::CloudFormation::Interface: 
      ParameterGroups: 
        -
          Label:
            default: Set a one-time password 
          Parameters:
            - paramOneTimePassword
      ParameterLabels:
        paramOneTimePassword:
          default: ' '
  
  ## =================== PARAMETERS ===================
  Parameters:
    paramOneTimePassword:
      Description: The user will have to pick a new password upon first sign in
      Type: String    
      NoEcho: 'true' # mask the parameter value as asterisks (*****) to prevent it from being displayed in the console, CLI, or API
      ConstraintDescription: Password must be between 8 and 32 characters, start with lowercase or uppercase letter, and can be alphanumeric with the following special characters !@#$%&
  
  ## =================== MAPPINGS ===================
  Mappings:
    mapUserData:
      UserName:
        AWS: testuser
        Real: 'Test User'
      Groups:
        Group: BackendDev
      Tags:
        product: testProduct
    mapManagedPolicies:
      CustomerManagedPolicies: 
        ARN: None
  
  ## =================== CONDITIONS ===================
  Conditions:
    hasManagedPolicy:
      !Not [!Equals [!FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], 'None'] ]
   
  ## =================== RESOURCES ===================
  Resources:
    # myInlinePolicyForChangeOwnPassword:
    #   Type: 'AWS::IAM::Policy'
    #   Properties:
    myUser:
      Type: 'AWS::IAM::User'
      Properties:
        UserName: !FindInMap [mapUserData, UserName, AWS]
        LoginProfile:
          Password: !Ref paramOneTimePassword 
          PasswordResetRequired: true 
        ManagedPolicyArns: # list of ARNs of IAM managed policies that you want to attach to the user
          - !If [ hasManagedPolicy, !FindInMap [mapManagedPolicies, CustomerManagedPolicies, ARN], !Ref "AWS::NoValue" ]
        Policies:
          - PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Sid: ViewAccountPasswordRequirements
                  Action: 'iam:GetAccountPasswordPolicy'
                  Resource: "*"
                - Effect: Allow
                  Sid: ChangeOwnPassword
                  Action:
                    - 'iam:GetUser'
                    - 'iam:ChangePassword'
                  Resource: !Join ['', [arn:aws:iam::*:user/,!FindInMap [mapUserData, UserName, AWS]]]
            PolicyName: IAM-ChangeOwnPassword
        Groups:
          - !FindInMap [mapUserData, Groups, Group]
        Tags:
          - Key: name
            Value: !FindInMap [mapUserData, UserName, Real]
          - Key: product
            Value: !FindInMap [mapUserData, Tags, product]
  
  ## =================== OUTPUT ===================
  Outputs:
    outputArn:
      Description: User ARN
      Value: !GetAtt myUser.Arn
    outputName:
      Description: User name
      Value: !Ref myUser
  
  ```
  
  
  ---
  
  