EC2インスタンスにIAMロールを自動アタッチする仕組みをテンプレート化してみた

2022.09.02

EC2インスタンスに「特定IAMロール」を必ず割り当てる仕組みを作ってみました。

作ったもの(構成図)

img

構成要素は以下のとおりです。

EC2ロール(インスタンスプロファイル)

自動アタッチさせたい EC2ロール(インスタンスプロファイル)です。

後述するテンプレートには以下権限を割り当てています。 SSMを活用する上である程度必要になってくる権限を付与しました。

  • CloudWatchAgentServerPolicy(AWS管理ポリシー)
  • AmazonSSMManagedInstanceCore(AWS管理ポリシー)
  • AmazonSSMPatchAssociation(AWS管理ポリシー)
  • Session Managerログ保管用バケット への PutObject/PutObjectAcl 権限

SSM State Manager 関連付け

Systems Manager(SSM) State Manager はインスタンスのあるべき状態を定義するものです。 この定義は 関連付け(Association) と言います。 関連付けには以下のような設定パラメータがあります。

  • 対象: どのインスタンスの状態を定義するか
  • 実行ドキュメント: どのドキュメントを実行するか
  • スケジュール: どの頻度で実行するか(or 1回のみの実施か)

今回は以下のような関連付け(および実行のためのSSMロール)を作りました。

  • 対象: すべてのインスタンス
  • 実行ドキュメント: AWS-AttachIAMToInstance
  • スケジュール: 1時間ごと

作ったもの(コード)

テンプレートがこちら。

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  # #####
  # Parameters for EC2 Role, Instance Profile
  # #####
  EC2RoleName:
    Type: String
    Default: "EC2DefaultRole"
  SSMSessionManagerLogBucketName:
    Type: String
    Default: "DOC-EXAMPLE-BUCKET"

  # #####
  # Parameters for SSM Role
  # #####
  SSMRoleName:
    Type: String
    Default: "SSMAutomationRole-AMIAttachToEC2"

  # #####
  # Parameters for SSM Association
  # #####
  AssociationName:
    Type: String
    Default: "auto-ec2-role-attach"
  ForceReplace:
    Type: String
    Default: "true"
    AllowedValues:
      - "true"
      - "false"

Resources:
  # #####
  # EC2 Role, Instance Profile
  # #####
  EC2Role:
    Type: AWS::IAM::Role
    Properties: 
      RoleName: !Ref EC2RoleName
      Description: "This role must be attached all EC2 instances."
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: "Allow"
            Principal: 
              Service: "ec2.amazonaws.com"
            Action: "sts:AssumeRole"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
        - "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
        - "arn:aws:iam::aws:policy/AmazonSSMPatchAssociation"
      Policies:       
        - PolicyName: S3Logging
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "s3:PutObject"
                  - "s3:PutObjectAcl"
                Resource: !Sub "arn:aws:s3:::${SSMSessionManagerLogBucketName}/*"
  EC2InstanceProfile: 
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Ref EC2Role
      Roles: 
        - !Ref EC2Role

  # #####
  # SSM Role for automation
  # #####
  SSMRole:
    Type: AWS::IAM::Role
    Properties: 
      RoleName: !Ref SSMRoleName
      Description: "role for SSM automation: EC2 role attach"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: "Allow"
            Principal: 
              Service: "ssm.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies: 
        - PolicyName: AWS-AttachIAMToInstance
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "ec2:DescribeIamInstanceProfileAssociations"
                  - "ec2:DisassociateIamInstanceProfile"
                  - "ec2:AssociateIamInstanceProfile"
                  - "iam:ListInstanceProfilesForRole"
                  - "iam:GetInstanceProfile"
                Resource: "*"
              - Effect: "Allow"
                Action: "iam:PassRole"
                Resource: !GetAtt EC2Role.Arn

  # #####
  # SSM Association
  # #####
  SSMAssociation:
    Type: AWS::SSM::Association
    Properties: 
      AssociationName: !Ref AssociationName
      Name: AWS-AttachIAMToInstance
      ApplyOnlyAtCronInterval: true
      ScheduleExpression: "cron(0 0/1 * * ? *)"
      Targets:
        - Key: InstanceIds
          Values:
            - "*"
      # Targets: 
      #   - Key: "tag:CCoEManaged"
      #     Values: 
      #       - "true"
      AutomationTargetParameterName: InstanceId
      Parameters:
        AutomationAssumeRole:
          - !GetAtt SSMRole.Arn
        ForceReplace:
          - !Ref ForceReplace
        RoleName:
          - !Ref EC2Role

パラメータには以下を指定します。

パラメータ名 説明
EC2RoleName EC2ロールの名前
SSMSessionManagerLogBucketName Session Manager のログ格納用バケットの名前
SSMRoleName SSMロールの名前
AssociationName SSM State Manager 関連付けの名前
ForceReplace 既存のEC2ロールを強制的に置換するか

試してみる

CFnテンプレートの展開

パラメータを入力してスタックを作成します。 (SSM Session Manager ログ用バケットは事前に準備必要です)

img

以下リソースが作られました。

img

EC2インスタンスを作成してみた

ロールを付与せずにEC2インスタンスを1つ作成しました。

時間を置いて見てみると、以下のようにロールが付与されていました。

img

次に「他のロール」をアタッチしてみました。

img

しばらくすると、以下のようにロールが付け替えられていました。

img

(もしロールの付替えを防ぎたい場合は CFnパラメータの ForceReplace を変えることで実現できるはずです。)

(参考) SSMのログ

SSM State Manager の関連付けからは実行履歴を見られます。

img

内部で実行している AWS-AttachIAMToInstance Automation のログは以下のようになります。

img

img

おわりに

「EC2インスタンスにIAMロールを自動アタッチする」仕組みを作ってみました。

ちなみに、EC2ロールの自動アタッチ自体は SSM高速セットアップで可能です。 そこでアタッチされるEC2ロールの権限が不足していて、カスタマイズしたい要件 がある場合に、この方法を試してみると良いと思います。

また、もし対象インスタンスを絞りたい場合は、 SSMAssociation の以下コメントしている部分に置き換えます。タグのキー/値に相当するインスタンスが対象になります。

      Targets:
        - Key: InstanceIds
          Values:
            - "*"
      # Targets: 
      #   - Key: "tag:CCoEManaged"
      #     Values: 
      #       - "true"

参考