Open11

AWS CDK issue 21197 - OIDCProvider L2 の再構成についてメモ

hassaku63hassaku63

issue: https://github.com/aws/aws-cdk/issues/21197

https://github.com/aws/aws-cdk/issues/21197

概要

CDK の OpenIdConnectProvider は CustomResource を使っている。

AWS::IAM::OIDCProvider を使った L2 に再構築したい。

議論

過去に PR を送った人がいたが、Feature flag に対応していなかったのでクローズされた。

aws-cdk issue#8607

https://github.com/aws/aws-cdk/issues/8607

L2 レベルの変更なので RFC が出ている

aws/aws-cdk-rfcs/issues/512

https://github.com/aws/aws-cdk-rfcs/issues/512

今提供している OIDCProvider L2 は、証明書のダウンロードと thumbprint の取得・検証を行っていて、そこが引き続き提供したい部分になる。

今 CustomResource でやっているのは CreateOpenIDConnectProvider API によるリソース作成と、証明書のダウンロード

本来の AWS::IAM::OIDCProvider を使う場合、後者の証明書 (というより thumbprint) 関係だけが残るので、それを CustomResource として残し、OIDCProvider は AWS::IAM::OpenIdConnectProvider にする方針が良い、と言っている。

hassaku63hassaku63

やんなきゃいけないことは;

Thumbprint

カスタムリソースの実装。

証明書のダウンロード部分だけ切り出して Construct にする必要がある。

関係しているのは、

packages/aws-cdk-lib/aws-iam/lib/oidc-provider/external.ts

downloadThumbprint のみ。

従来の L2 (CustomResource) では onCreate, onUpdate で呼び出しが入っている。

onCreate, onUpdate のどちらも、thumbprint の引数がない場合のデフォルト挙動としてこれが入っている。

OIDCProvider リソースとしての return は以下

https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-iam/lib/oidc-provider/index.ts#L26-L31

AWS User Guide - CustomResource によれば $.Data 以下の key-value は Fn::GetAtt によって取得可能とのこと

一方、ネイティブリソースでは GetAtt できるものは異なる様子。 Arn しか返せない。

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-oidcprovider.html

ここは今は(重要度が相対的に小さく見えるので)考えないようにする。

hassaku63hassaku63

Thumbprint を Construct で構成する場合、なにが必要になるか??

実質的に downloadThumbprint の結果を引っ張ってくることだけなので、ダウンロードしてその戻り値を CsutomResource の戻り値として返す実装があれば良い、といえそう

hassaku63hassaku63

RFC では Thumbprint を L2 に切り出す、と言っているが考えること増えててあんまり良くないんじゃない?

...と思っている。普通に Construct を作成するタイミングで作るのではダメなのか。

AWS API を叩くようなものではないので、問題があるとすれば synth, deploy する際の実行環境がインターネットに出られることを要求することくらい。とはいえすでに外部通信を要求する話はあるので大きな問題ではないように見える。

hassaku63hassaku63

いったん、Thumbprint 用の Construct は切らない方針で実装してみようと思う

hassaku63hassaku63

「なんで Thumbprint をわざわざ Construct にするのか、OIDCProvider L2 で直接呼べばいいじゃないか」

と思っていたんだけど、これすると非同期が必須になる。このへんが jsii の制約か何かに引っかかるのではないか?という仮説を立てた。

https://aws.github.io/jsii/user-guides/lib-author/typescript-restrictions/

このへん流し読みしてみる。

あるいは、Intro から参照のある Author Guide あたりにありそう

hassaku63hassaku63

テーマ: jsii だと Construct に非同期は使えない制約がある?


まずは jsii の概要を調べる

トップページ に、

jsii allows code in any language to naturally interact with JavaScript classes. It is the technology that enables the AWS Cloud Development Kit to deliver polyglot libraries from a single codebase!

と書いてあった。てっきりトランスパイルするものだと思っていたけど、実際には他の言語から JavaScript への FFI 的なものっぽい?

Runtime Architecture の図を見ると実際そうっぽい。CDK TypeScript が各種対応言語向けの binding を生成していて、実際の機能は jsii Runtime によって JavaScript 側にある機能の実体と通信することで提供されている様子がわかる

┌─────────────────────────┐               ┌────────────┬────┬────┬────┐
│                         │               │            │    │    │    │
│    Host Application     │               │@jsii/kernel│LibA│LibB│... │
│                         │               │            │    │    │    │
│      ┌──────────────────┤               ├────────────┴────┴────┴────┤
│      │                  │               │                           │
│      │Generated Bindings│               │       @jsii/runtime       │
│      │                  │               │                           │
│      ├──────────────────┤   Requests    ├──────┬────────────────────┤
│      │                  ├───────────────▶STDIN │                    │
│      │Host jsii Runtime │   Responses   ├──────┤                    │
│      │     Library      ◀───────────────┤STDOUT│                    │
│      │                  │    Console    ├──────┤    node            │
│      │                  ◀───────────────┤STDERR│                    │
├──────┴──────────────────┤               ├──────┘                    │
│      Host Runtime       │               │      (Child Process)      │
│  (JVM, .NET Core, ...)  │               │                           │
│                         │               │                           │
├─────────────────────────┴───────────────┴───────────────────────────┤
│                                                                     │
│                          Operating System                           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

jsii の制約はTypeScript Restrictions に書いてある

クラスのプロパティには、PascalCased なクラス名と同名のものを宣言できない

// 例
export class Foo {
  public foo: string;
}

interface は2種類の用法が許されている

kind description Naming
Behavioral メソッド、プロパティを持てる I で始まる名前
Struct イミュータブルなデータエンティティ。readonly プロパティしか宣言できない I で始まらない名前

Struct の場合は、同じ Struct タイプの interface を extend することができる

オーバーライドされたメンバーは元のメンバーと同じ可視性を持つ

index signatures が使えない

export interface WithIndexSignature {
  public readonly name: string;

  // 💥 Index signatures are not supported
  public [key: string]: unknown;
}

(これ index signature ていうのか...)

ジェネリック使った型は宣言できない

// 💥 Parameterized types cannot be introduced
export interface Parameterized<T> {
  readonly value: T;
}

export interface IAsyncFooMaker {
  // ✅ Asynchronous methods must return promises
  makeFoo(): Promise<Foo>;
  // ✅ Arrays are supported
  makeFoos(count: number): Array<Promise<Foo>>;
}

非同期メソッドは Promise の戻り値なら使える。Array も OK

Type alias は TypeScript の中でだけ使える。使えはする。

// 👻 Only visible in TypeScript
export type FooOrBar = Foo | Bar;

export interface Props {
  // ⚠️ Effectively `readonly fooOrBar: Foo | Bar;` in non-TypeScript
  readonly fooOrBar: FooOrBar;
}

他の言語の予約語に被る

jsii が警告を出す


Primise なら非同期も行けそう。

hassaku63hassaku63

同僚氏が最近書いた PR が割といい感じなのでこれを見ながら変更すべき場所にアタリを付けていく

https://github.com/aws/aws-cdk/pull/25697/files

Thumbprint Construct のテストどう書くか作戦

とりあえず2種類のテストを書かなくちゃならない

(1) Construct 単体のテスト

packages/aws-cdk-lib/aws-iam/test/oidc-provider.test.ts が既存のやつ。

Feature Flag 有効化した場合の挙動を足す必要がある

(2) Integ Test

packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.oidc-provider.ts が既存のやつ。

hassaku63hassaku63

Slack 見てみると、OIDC Provider について会話している履歴があった。
急がないと先を越されそう。

https://cdk-dev.slack.com/archives/C018XT6REKT/p1686402375400699

If I'm working on contributing a change to https://github.com/aws/aws-cdk/, is there a way I can rebuild only the subsets of aws-cdk-lib that I've changed? For example, if I change aws-cdk/packages/aws-cdk-lib/aws-iam/lib/oidc-provider.ts, is there a command I can run other than yarn build from aws-cdk-lib/, that will be faster?

回答がこれ。デフォルトでいけるっぽい

Yes. I think that's the default. Don't remember the exact command, but it only builds that package and its dependencies.

because the yarn build works in that context onl