[レポート] ワークショップ – GitHub Actionsを使ったIAMポリシーの検証と分析の自動化 #IAM452 #AWSreInforce

2024.06.14

あしざわです。

米国フィラデルフィアで開催されている AWS re:Inforce 2024 に参加しています。

本記事は AWS re:Inforce 2024 のワークショップ 「Automating IAM Policy Validation and Analysis using GitHub Actions」のレポートです。

セッション概要

In this builders’ session, learn how to automate the validation of AWS Identity and Access Management (IAM) policies using the IAM Policy Validator for AWS CloudFormation (cfn-policy-validator). Policy validation and analysis minimize the deployment of unwanted IAM policies. While security teams oversee the organizational security posture, developers create applications that need permissions. To help developers work quickly without compromising on security posture, organizations delegate developer IAM policy authoring. By combining automated validation and analysis with delegated developer permissions, organizations can gain more secure development velocity. Learn how cfn-policy-validator and GitHub Actions can automatically validate and analyze IAM policies when permitting developer policy authoring abilities without compromising security. You must bring your laptop to participate.

ワークショップで体験したこと

このワークショップでは、GitHub Actionsを用いてCloudFormationテンプレートで定義されたIAMリソースの自動ポリシーチェックを体験できました。

全体の流れを簡単に説明したものがこちらです。

  1. Sagemaker StudioからGitHub上のリポジトリにCloudFormationテンプレートをCommit/Pushします
  2. リポジトリに設定されたGitHub Actionワークフローがトリガーされます
  3. ワークフローの中でIAM Access Analyzer のカスタムポリシーチェック(CheckNoNewAccess)が動作します
  4. チェック結果がPassとなればOK、FailedとなればNGです

CheckNoNewAccessとは、IAM Access Analyzerのカスタムポリシーチェックの1種です。既存のポリシーと比較して、更新されたポリシーに対して新しいアクセスが許可されているかどうかを確認できます。通常、既存のポリシー・更新されたポリシーの両方をJSONのIAMポリシーの形式でファイルとして保存し、比較する必要があります。

## AWS CLIで実行する場合のイメージ
aws accessanalyzer check-no-new-access \
    --existing-policy-document file://existing-policy.json \ ##既存のポリシー
    --new-policy-document file://new-policy.json \ ##更新されたポリシー
    --policy-type IDENTITY_POLICY

今回のワークショップでは、aws-cloudformation-iam-policy-validatorというawslabsのGitHubリポジトリで継続的に更新されているツール利用します。このツールを利用すれば、CheckNoNewAccessによる比較対象としてCloudFormationテンプレートを指定できます。

ここでは前者の既存のポリシー(--existing-policy-document)をリファレンスファイルとして事前にS3バケットに保存し、後者の更新されたポリシー(--new-policy-document)としてGitHubリポジトリにCommit&PushされたCFnテンプレートを利用します。

システム構成図

全体のシステム構成図はこちら。

ワークショップの流れ

ワークショップは、事前準備・課題1・課題2という3つのフェーズで構成されていました。

課題フェーズは2つのパターンがありましたが、多少リファレンスファイルやCFnテンプレートの内容に差があるくらいで対応する流れは同様でした。なので、レポートは課題1のみとし、課題2についてはこのレポートで記載しません。

事前準備

事前準備フェーズでは、こちらの作業を行いました。

  1. GitHubリポジトリの作成
  2. Sagemaker Studio のCode Editor で作成したリポジトリをClone
  3. GitHub Actions用のAWSクレデンシャルを発行
  4. IAM Access Analyzer APIを呼び出すためのIAMロールを作成

1、2については特に目新しいことはやっていないので割愛します。

3では、まずIAMのIDプロバイダにGitHub Actions用のプロバイダ( https://token.actions.githubusercontent.com )を作成し、対象をSTS( sts.amazonaws.com )とします。

4では、まず作成したIDプロバイダのプロバイダ名と対象者(Audience)、GitHubユーザー名(もしくはOrganization名)、GitHubリポジトリ名を入力して、IAMロールを作成します

ここでGitHubリポジトリがプライベート設定だった場合、GitHub Actions用のSecretとして追加の設定が必要になります。対象のGitHubリポジトリのSettings > Security > Secrets and variables > Actionsから以下を設定してください。

  • Name: OIDC_IAM_ROLE
  • Secret: arn:aws:iam::<accountID>:role/<rolename>

準備は以上です。

課題

ここからがワークショップの本題である課題フェーズです。

本題と言いながら再び環境構築フェーズです。

まずはSagemaker StudioのCode Editorを利用して、各ファイルを作成していきます。

にはデプロイ先のリージョンを入力してください。

.github/workflows

name: cfn-policy-validator-workflow

on:
  pull_request:
    types: [opened, review_requested]

  push:
    branches:
      - 'main'

permissions:
  id-token: write
  contents: read
  issues: write

jobs: 
  cfn-iam-policy-validation: 
    name: iam-policy-validation
    runs-on: ubuntu-latest
    permissions: write-all
    steps:
      - name: Checkout code
        id: checkOut
        uses: actions/checkout@v4

      - name: Configure AWS Credentials
        id: configureCreds
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.OIDC_IAM_ROLE }}
          aws-region: <AWSRegion> ##<AWSRegion>には利用中のリージョンを入力
          role-session-name: GitHubSessionName
        
      - name: Fetch reference policy from s3
        id: getReferencePolicy
        run: |
          aws s3 cp ${{ secrets.REFERENCE_IDENTITY_POLICY }} ./reference-identity-policy.json
        shell: bash
          
      - name: Run AWS AccessAnalyzer CheckNoNewAccess check
        id: run-aws-check-no-new-access
        uses: aws-actions/cloudformation-aws-iam-policy-validator@v1.0.1
        with:
          policy-check-type: 'CHECK_NO_NEW_ACCESS'
          template-path: './sample-role.yaml'
          reference-policy: './reference-identity-policy.json'
          reference-policy-type: "IDENTITY"
          region: <AWSRegion> ##<AWSRegion>には利用中のリージョンを入力

次はリファレンスファイルを作成、S3バケットに配置します。

~/reference-identity-policy.json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        },
        {
            "Effect": "Deny",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::*:role/my-sensitive-roles/*"
        }
    ]
}

続いて、GitHub Secretにリファレンスポリシーを配置したS3のURLなどを設定します。

  • Name: REFERENCE_IDENTITY_POLICY
  • Secret: s3://<ConfigBucket>/reference-identity-policy.json

この環境に対し、以下のファイルを作成し、Commit/Pushします。

./sample-role.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: IAM452 Sample CloudFormation
Resources:
  SampleIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              AWS: "*"
            Action: ["sts:AssumeRole"]
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "dynamodb:Scan"
                  - "dynamodb:Query"
                  - "dynamodb:UpdateItem"
                  - "dynamodb:GetItem"
                  - "dynamodb:DeleteTable"
                Resource: "*"
              - Effect: Allow
                Action:
                  - "iam:PassRole"
                Resource: "arn:aws:iam::*:role/my-sensitive-roles/adminrole452"

すると、エラーになりました。何が問題だったのでしょうか???

Run AWS AccessAnalyzer CheckNoNewAccess checkで出ていたエラー内容がこちらです。

result={"BlockingFindings": [{"findingType": "SECURITY_WARNING","code": "policy-analysis-CheckNoNewAccess","message": "The modified permissions grant new access compared to your existing policy.","resourceName": "SampleIamRole","policyName": "root","details": {"result": "FAIL","message": "The modified permissions grant new access compared to your existing policy.","reasons": [{"description": "New access in the statement with index: 1.","statementIndex": 1}]}}],"NonBlockingFindings": []}

問題はこの箇所にありました。

              - Effect: Allow
                Action:
                  - "iam:PassRole"
                Resource: "arn:aws:iam::*:role/my-sensitive-roles/adminrole452"

リファレンスファイルではarn:aws:iam::*:role/my-sensitive-roles/*はDenyされているので、「〜my-sensitive-roles/adminrole452」がAllowされてしまっているCFnテンプレートでは権限を超えてしまう(NewAccessが生まれてしまう)わけです。なので、CheckNoNewAccessで違反となります。

        {
            "Effect": "Deny",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::*:role/my-sensitive-roles/*"
        }

該当の箇所をセクションごと削除して以下のファイルに修正し、再度Commit&Pushしました。

./sample-role.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: IAM452 Sample CloudFormation
Resources:
  SampleIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              AWS: "*"
            Action: ["sts:AssumeRole"]
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "dynamodb:Scan"
                  - "dynamodb:Query"
                  - "dynamodb:UpdateItem"
                  - "dynamodb:GetItem"
                  - "dynamodb:DeleteTable"
                Resource: "*"

ワークフローが実行され、次はエラーが解消されていました。

おわりに

以上、「Automating IAM Policy Validation and Analysis using GitHub Actions」のレポートでした。

GitHub ActionsおよびIAM Access Analyzerをあまり使ったことがなかったため、入門ワークショップとして最適なセッションでした。非常に参考になりました。

今回のre:Inforceでは、ポリシーを自動チェック・デプロイする仕組みとして以下の構成を設定し、SCPを安全にデプロイする構成を紹介するセッションがありました。

  • CI/CDパイプライン: CodePipeline
  • ビルド: CodeBuild
  • ポリシーチェック: terraform-iam-policy-validator

terraform-iam-policy-validatorは本セッションでも紹介されていた、CFnテンプレートではなくTerraformテンプレートをIAMポリシーの解析対象として分析できるツールです。Terraformを利用しているプロジェクトに自動ポリシーチェックの仕組みを導入する場合はこちらの方がマッチしそうです。

紹介した別セッションのレポートもブログにしていますので合わせてご覧ください。

あしざわでした。