Open8

[AWS CDK] Security And Safety Dev Guide を通読する

hassaku63hassaku63

Introduction

CDK を使うことで様々なリソースが操作できるようになる。

開発者にとっての利便性(生産性)と、組織がガバナンス統制として求めるセキュリティあるいはコスト管理の要請事項の間にはトレードオフがある。

これを両立するために取れる(推奨される)選択肢をこのページでは提示している。おそらくほとんどのユースケースをカバーできるはずである。

以下の観点を取り上げる。

  • What permissions to extend to CDK deployments
  • How to control the permissions of CDK deployments via IAM identities and policies
  • How to use CDK to configure the IAM identities and policies of deployed applications
  • Using Permissions Boundaries with CDK
hassaku63hassaku63

What permissions should I give to CDK deployments?

開発者に権限を与えるやり方には allow listting/ deny listing の2通りのアプローチがある。また、CDK プロジェクトのデプロイに対して新しい IAM Role を用意すべきかどうかの議論がある。

※権限を制限すること自体がゴールあることはほとんどなく、意図しない操作によって発生する事故を防ぐためである、という前提で書かれている

allow linting によるアプローチは様々な課題があり、推奨できない(直感的に考えてもそうだと思うので、具体的な中身は訳さず原文に譲る)

deny listing アプローチが推奨される。これは AWS Config, AWS CloudTrail, AWS Security Hub, AWS CloudFormation Hooks などを用いる。認められたコンプライアンスの範囲内であれば開発者に自由を持たせることができる。

Allowing creation of IAM Roles without privilege escalation

「開発者に IAM Role の作成を許可すべきか?」という質問がよく出てくる。

これは、許可しないことによるデメリットがいくつかある。詳細は原文に譲るとして、以下のような悪い影響をもたらす

  • 開発速度が低下する
  • Security Posture が悪化する(セキュリティの要請に対応するための態勢として好ましくない状態になる、と理解。CSPM 的な話?)

※2点目の観点は、言語化されれば「確かに」とすぐ納得できるが、想像はできていなかったので学びがあった

ここでの目的意識は、開発者に権限昇格させないためのルールを設けることである。Role の作成を禁止する代替として、Permission Boundary や SCP を用いたアプローチが可能である。

hassaku63hassaku63

Controlling the permissions used by CDK deployments

デプロイの引き金を引く "Actor" が必ず関与している。Actor が1つ以上の IAM User/Role を引き受けてデプロイする。オプションで PassRole することもできる。

CDK がデプロイ時にどのようなロールを使用するのかは、Stack Synthesizer で決定される。

以降は Default Synthesizer の仕様を bootstrap も含めて解説するセクション。詳しいことは省略するが、CloudFormation のデプロイや Image Asset の作成に必要なロールをそれぞれ使っている様子が図示されているのでそれだけ載せておく。

CloudFormation のデプロイが頻出しそうなので個別に補足。重要なのはアクターが持っている認証情報が確認できたあと、 デプロイ用 Role を引き受けたうえでデプロイ実行用に用いる Role を PassRole で渡している こと。

「デプロイに用いる Role」と「デプロイの実行時に用いる Role」が異なる。

いくつかの利点がある。

  • 「デプロイ」という操作にアクセスできる Actor を、Deploy Role に AssumeRole できる人に限定できる
  • PassRole とすることで、実際にリソースを作成するために必要なロールを個々の Actor に渡さなくてよくなる
  • Deploy Role を AssumeRole 前提とすることで、クロスアカウントのデプロイが可能になる

CloudFormation のデプロイ以外の話も少しだけ補足。上図中の上と下に伸びる矢印がそれ。

(1) Asset を公開するための Role

コンテナイメージや S3 へのアップロードを行う処理が該当する。File upload と Image publish でそれぞれ1つずつ Role を作成。

(2) Lookup

Synth の実行時にリソース参照が必要な場合に Lookup 用の Role が利用される。デフォルトでは RO 権限

hassaku63hassaku63

デプロイに関係する権限にどんなものがあるかが前のコメントに書いてあるセクションで判明した。

で、開発者にどういった権限を与えるのか?という課題への回答が bootstrap プロセスで作成する Role を制御することにある、というのも見えてくる。

あと、bootstrap 自体を実行する Role に対して権限を縛ることにほぼ意味がなさそう、ということもわかる。bootstrap がワンショットのタスクであることもあるが、実際にデプロイ時に使っている権限は別のアイデンティティであるため。

Bootstrapping

bootstrap で使われるデフォルトのテンプレートをカスタマイズすることで、コンプライアンス制御を介入させることができる。

https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html#bootstrapping-customizing

bootstrap された Role を引き受けるため(=Default Synthesizer を使ったデプロイができること、と解釈)には、以下のようなポリシーを持つ Role が必要。

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AssumeCDKRoles",
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "*",
    "Condition": {
      "ForAnyValue:StringEquals": {
        "iam:ResourceTag/aws-cdk:bootstrap-role": [
          "image-publishing",
          "file-publishing",
          "deploy",
          "lookup"
        ]
      }
    }
  }]
}

デプロイ対象のアカウントでの bootstrap さえ済んでいるなら、CDK プロジェクトのデプロイを行う人が持つべき権限はこれだけ、ということになる。

Bootstrap はアカウント管理者(開発者ではない)が実行するただ1回のタスクである。Admin 権限を使うことを推奨する。
また、Bootstrap プロセスで行っていることは将来拡張する可能性があるし、どのような変更が発生するかを予想することはできない。

Bootstrap はその設計上、任意のポリシーを持った Role を作成する。権限を制限することにメリットはないであろう。

もし、それでも、Bootstrap に対する権限を縛りたい場合は最低限以下のようなポリシーを当てることになる。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:*",
                "ecr:*",
                "ssm:*",
                "s3:*",
                "iam:*"
            ],
            "Resource": "*"
        }
    ]
}
hassaku63hassaku63

CliCredentialsStackSynthesizer

https://github.com/aws/aws-cdk/wiki/Security-And-Safety-Dev-Guide#clicredentialsstacksynthesizer

Default Synthesizer に替わる選択肢。CDK CLI が利用している Role をそのまま全部のデプロイタスクに使うよ、というもの。

もっともわかりやすいデプロイ方法であり、また Serverless Framework を(特に工夫せずに)使った場合のデプロイ方法でもある(はず)。

なので、CLI を実行しているプロファイルが CFn デプロイとそのデプロイによってプロビジョニングされる全てのリソースに関する作成・変更権限を持っている必要がある。


感想)
CliCredentialsStackSynthesizer は最も原始的なデプロイ権限の管理方法。ただ、こちらは CDK のデフォルト仕様ではないし、デフォルトの方式がよりベスプラに沿っていると思うのであえてこちらを選択すべきメリットはないように思う。

hassaku63hassaku63

Letting the CDK manage IAM Roles and Policies

スタックの中で IAM Role, Policy を作らせるかどうかの議論がここのセクションで触れられている。

基本は CDK が自動で必要な権限を付与してくれるようになっていて、そこに従うのが推奨。

どうしても Role/Policy を作らせたくないなら、事前に必要なものを作成しておいて CDK プロジェクトからはそのリソースを参照させる方式で実装することになる。
(直感的にすごく大変そう。開発・運用のいかなる場面でもオーバーヘッドが大きそう)

書き方は Referencing and managing Roles by hand のセクションに出てくるサンプルコードを参照。

また、Role に関する Synthesize だけをやらないようにする方法も用意されているらしい。

iam.Role.customizeRoles() がそれだが、ここはまず採用する機会がない気がするので読むのは省略する。

hassaku63hassaku63

Controlling the permissions used by CDK deployments で言及されたデプロイに用いる Role の話が、

実際に bootstrap する CFn スタックの変数とドキュメント を突合することで理解できてきた

https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html

bootstrap で実行される CFn テンプレートは以下のコマンドで確認可能

cdk bootstrap --show-template

例えば、Bootstrap スタックに存在する FilePublishingRole

  FilePublishingRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              AWS:
                Ref: AWS::AccountId
          # "TructedAccounts" が指定されている場合に以下のプリンシパルに AssumeRole の許可を与えている
          - Fn::If:
              - HasTrustedAccounts
              - Action: sts:AssumeRole
                Effect: Allow
                Principal:
                  AWS:
                    Ref: TrustedAccounts
              - Ref: AWS::NoValue

デプロイをトリガーできる Role DeploymentActionRole でもおよそ同様の実装になっている模様。

  DeploymentActionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              AWS:
                Ref: AWS::AccountId
          - Fn::If:
              - HasTrustedAccounts
              - Action: sts:AssumeRole
                Effect: Allow
                Principal:
                  AWS:
                    Ref: TrustedAccounts
              - Ref: AWS::NoValue
      Policies:
        # ...

If 文で、 HasTrustedAccounts を満たす場合は Parameter TrustedAccounts のアカウントを AssumeRole してよいリストに追加している。

おそらくこれは bootstrap のドキュメントにある以下のオプションと対応している。

--trust lists the AWS accounts that may deploy into the environment being bootstrapped.
Use this flag when bootstrapping an environment that a CDK Pipeline in another environment will deploy into. The account doing the bootstrapping is always trusted.

Bootstrap する際に --trust にアカウント "A" を与えると、その bootstrap したアカウントに対してアカウントAのプリンシパルは FilePublishing を実行できる(厳密には FilePublishingRole を AssumeRole できる)ようになる。