cfn-policy-validator を使ってCLIで「外部アクセス許可の検証」をしてみた

2021.09.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いわさです。

IAM Access Analyzerを使うとリソースの意図しないパブリックアクセス、クロスアカウントアクセスの原因となるリソースポリシーの検出が可能です。

以前、チバユキさんがブログを書かれていました。

上記ではマネジメントコンソール上で確認をされています。 チバユキさんもブログの中で、CLIから検出を実施する場合はCreateAccessPreviewを使う必要があるよう言及されています。

そして、APIをラップしたcfn-policy-validatorなるツールが登場したそうなので手軽に検出出来るようになったようです。

本日は試してみました。

インストール

Python製のツールで、pipよりすぐセットアップして使えるようになります。

iwasa.takahito@hoge ~ % pip install cfn-policy-validator
Collecting cfn-policy-validator
  Downloading cfn_policy_validator-0.0.2-py3-none-any.whl (69 kB)
     |████████████████████████████████| 69 kB 1.5 MB/s 
Collecting pyYAML>=5.3
  Downloading PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl (259 kB)
     |████████████████████████████████| 259 kB 2.5 MB/s 
Requirement already satisfied: urllib3>=1.25 in ./.pyenv/versions/3.9.4/lib/python3.9/site-packages (from cfn-policy-validator) (1.26.4)
Collecting jsonschema>=3.2
  Downloading jsonschema-4.0.0-py3-none-any.whl (69 kB)
     |████████████████████████████████| 69 kB 4.8 MB/s 
Requirement already satisfied: boto3>=1.17 in ./.pyenv/versions/3.9.4/lib/python3.9/site-packages (from cfn-policy-validator) (1.18.35)
Requirement already satisfied: s3transfer<0.6.0,>=0.5.0 in ./.pyenv/versions/3.9.4/lib/python3.9/site-packages (from boto3>=1.17->cfn-policy-validator) (0.5.0)
Requirement already satisfied: botocore<1.22.0,>=1.21.35 in ./.pyenv/versions/3.9.4/lib/python3.9/site-packages (from boto3>=1.17->cfn-policy-validator) (1.21.35)
Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in ./.pyenv/versions/3.9.4/lib/python3.9/site-packages (from boto3>=1.17->cfn-policy-validator) (0.10.0)
Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in ./.pyenv/versions/3.9.4/lib/python3.9/site-packages (from botocore<1.22.0,>=1.21.35->boto3>=1.17->cfn-policy-validator) (2.8.1)
Collecting pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0
  Downloading pyrsistent-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl (68 kB)
     |████████████████████████████████| 68 kB 3.1 MB/s 
Collecting attrs>=17.4.0
  Downloading attrs-21.2.0-py2.py3-none-any.whl (53 kB)
     |████████████████████████████████| 53 kB 2.9 MB/s 
Requirement already satisfied: six>=1.5 in ./.pyenv/versions/3.9.4/lib/python3.9/site-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.22.0,>=1.21.35->boto3>=1.17->cfn-policy-validator) (1.16.0)
Installing collected packages: pyrsistent, attrs, pyYAML, jsonschema, cfn-policy-validator
Successfully installed attrs-21.2.0 cfn-policy-validator-0.0.2 jsonschema-4.0.0 pyYAML-5.4.1 pyrsistent-0.18.0

検出出来るのはマネジメントコンソールと同様で、バケットポリシー、KMSキー、SQSキューポリシーなど様々です。
詳細は以下をご確認ください。

ためしてみた

外部プリンシパルの指定あり

では早速、外部のIAMユーザーを指定したバケットポリシーを作成してみます。

AWSTemplateFormatVersion: "2010-09-09"

Resources:
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: iwasa-app-artifacts

  ArtifactBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref ArtifactBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Action: "*"
            Effect: Allow
            Resource: "arn:aws:s3:::iwasa-app-artifacts/*"
            Principal:
              AWS: "arn:aws:iam::999999999999:user/iwasa"

cfn-policy-validatorコマンドにCloudFormationテンプレートファイルを指定して実行します。

iwasa.takahito@hoge policy-validator % cfn-policy-validator validate --template-path ./01_template.yaml --region ap-northeast-1 --profile hoge
{
    "BlockingFindings": [
        {
            "findingType": "SECURITY_WARNING",
            "code": "EXTERNAL_PRINCIPAL",
            "message": "Resource policy allows access from external principals.",
            "resourceName": "iwasa-app-artifacts",
            "policyName": "BucketPolicy",
            "details": {
                "action": [
                    "s3:AbortMultipartUpload",
                    "s3:BypassGovernanceRetention",
                    "s3:DeleteBucket",
                    ...省略...
                    "s3:ReplicateObject",
                    "s3:ReplicateTags",
                    "s3:RestoreObject"
                ],
                "changeType": "NEW",
                "condition": {},
                "createdAt": "2021-09-30T11:52:04+00:00",
                "id": "11111111-1111-1111-1111-111111111111",
                "isPublic": false,
                "principal": {
                    "AWS": "arn:aws:iam::999999999999:user/iwasa"
                },
                "resource": "arn:aws:s3:::iwasa-app-artifacts",
                "resourceOwnerAccount": "123456789012",
                "resourceType": "AWS::S3::Bucket",
                "sources": [
                    {
                        "type": "POLICY"
                    }
                ],
                "status": "ACTIVE"
            }
        }
    ],
    "NonBlockingFindings": []
}

SECURITY_WARNINGが発生しましたね。
外部プリンシパルからのアクセスが許可されているとメッセージに表示されています。

外部アクセスなし

外部プリンシパルを指定しなかった場合はどうなるでしょうか。

AWSTemplateFormatVersion: "2010-09-09"

Resources:
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: iwasa-app-artifacts

  ArtifactBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref ArtifactBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Action: "*"
            Effect: Allow
            Resource: "arn:aws:s3:::iwasa-app-artifacts/*"
            Principal:
              AWS: "arn:aws:iam::123456789012:user/hoge"
iwasa.takahito@hoge policy-validator % cfn-policy-validator validate --template-path ./01_template.yaml --region ap-northeast-1 --profile hoge
{
    "BlockingFindings": [],
    "NonBlockingFindings": []
}

エラーメッセージが何も出なくなりましたね。

AllowかつNotPrincipalを使用

NotPrincipalでAllowを指定してみましょう。
この組み合わせは個別に検出されて専用メッセージが出力されます。

AWSTemplateFormatVersion: "2010-09-09"

Resources:
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: iwasa-app-artifacts

  ArtifactBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref ArtifactBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Action: "*"
            Effect: Allow
            Resource: "arn:aws:s3:::iwasa-app-artifacts/*"
            NotPrincipal:
              AWS: "arn:aws:iam::999999999999:user/iwasa"
iwasa.takahito@hoge policy-validator % cfn-policy-validator validate --template-path ./01_template.yaml --region ap-northeast-1 --profile hoge
{
    "BlockingFindings": [
        {
            "findingType": "SECURITY_WARNING",
            "code": "ALLOW_WITH_NOT_PRINCIPAL",
            "message": "Using Allow with NotPrincipal can be overly permissive. We recommend that you use Principal instead.",
            "resourceName": "iwasa-app-artifacts",
            "policyName": "BucketPolicy",
            "details": {
                "findingDetails": "Using Allow with NotPrincipal can be overly permissive. We recommend that you use Principal instead.",
                "findingType": "SECURITY_WARNING",
                "issueCode": "ALLOW_WITH_NOT_PRINCIPAL",
                "learnMoreLink": "https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-reference-policy-checks.html#access-analyzer-reference-policy-checks-security-warning-allow-with-not-principal",
                "locations": [
                    {
                        "path": [
                            {
                                "value": "Statement"
                            },
                            {
                                "index": 0
                            },
                            {
                                "value": "Effect"
                            }
                        ],
                        "span": {
                            "end": {
                                "column": 73,
                                "line": 1,
                                "offset": 73
                            },
                            "start": {
                                "column": 66,
                                "line": 1,
                                "offset": 66
                            }
                        }
                    },
                    {
                        "path": [
                            {
                                "value": "Statement"
                            },
                            {
                                "index": 0
                            },
                            {
                                "value": "NotPrincipal"
                            }
                        ],
                        "span": {
                            "end": {
                                "column": 188,
                                "line": 1,
                                "offset": 188
                            },
                            "start": {
                                "column": 141,
                                "line": 1,
                                "offset": 141
                            }
                        }
                    }
                ]
            }
        },
        {
            "findingType": "SECURITY_WARNING",
            "code": "EXTERNAL_PRINCIPAL",
            "message": "Resource policy allows access from external principals.",
            "resourceName": "iwasa-app-artifacts",
            "policyName": "BucketPolicy",
            "details": {
                "action": [
                    "s3:AbortMultipartUpload",
                    "s3:BypassGovernanceRetention",
                    "s3:DeleteBucket",
                    "s3:DeleteBucketOwnershipControls",
                    "s3:DeleteBucketWebsite",
                    "s3:DeleteObject",
                    ...
                    "s3:ReplicateObject",
                    "s3:ReplicateTags",
                    "s3:RestoreObject"
                ],
                "changeType": "NEW",
                "condition": {},
                "createdAt": "2021-09-30T12:14:55+00:00",
                "id": "11111111-1111-1111-1111-111111111111",
                "isPublic": true,
                "principal": {
                    "AWS": "*"
                },
                "resource": "arn:aws:s3:::iwasa-app-artifacts",
                "resourceOwnerAccount": "123456789012",
                "resourceType": "AWS::S3::Bucket",
                "sources": [
                    {
                        "type": "POLICY"
                    }
                ],
                "status": "ACTIVE"
            }
        }
    ],
    "NonBlockingFindings": []
}

ALLOW_WITH_NOT_PRINCIPALということで警告が発生しましたね。
親切に、learnMoreLinkを確認するとALLOW_WITH_NOT_PRINCIPALに対する対策内容が確認出来ます。

この辺りの検出内容はひととおり対応されていそうです。

さいごに

検出結果が抽出された場合はパイプラインを中断するなど、IAM Access Analyzerの外部アクセスポリシー検出機能をCI/CDパイプラインに組み込みやすくなりました。
他にも、cfn-lintやCloudFormation Guardを併せて組み込むことで厳格なデプロイパイプラインを構築出来そうです。

参考

Validate IAM policies in CloudFormation templates using IAM Access Analyzer | AWS Security Blog