eksctl で Kubernetes 1.23 の Amazon EKS クラスターを作成する
2022年8月11日に、Amazon Elastic Kubernetes Service ( Amazon EKS ) で Kubernetes のバージョン 1.23 がサポートされました。
そこで、早速 バージョン 1.23 の EKS クラスターを作成しようと思ったのですが、その時点ではまだ eksctl が対応していないことが判明しました。
1.23 のサポートがアナウンスされた後に、eksctl のバージョンはアップグレードしたのですが、次のように、eksctl のバージョンが 1.0.8 以下の場合、eksctl で EKS クラスターを作成しようとすると指定バージョンが対象外であるとエラーになります。
$ eksctl version 0.108.0 $ eksctl create cluster \ > --name test123-cluster \ > --vpc-public-subnets subnet-0b10715b2edf27dde,subnet-023105dfe3f0a2bdb \ > --nodegroup-name test123-nodes \ > --node-type t3.small \ > --nodes 2 \ > --nodes-min 1 \ > --nodes-max 3 \ > --managed \ > --version 1.23 \ > --region ap-northeast-1 2022-08-26 13:28:34 [ℹ] eksctl version 0.108.0 2022-08-26 13:28:34 [ℹ] using region ap-northeast-1 Error: invalid version, supported values: 1.19, 1.20, 1.21, 1.22
EKS で サポートされる Kubernetes のバージョンが追加されたからといって、同時に そのバージョンに対応した eksctl がリリースされているわけではないんですね。
で、約 2週間ほど経って、 eksctl のリリース情報を確認すると、どうやら バージョン 1.109.0 で Kubernetes のバージョン 1.23 に対応したことがわかりました。
この eksctl のリリース情報をみると、EKS で 1.23 のサポートがアナウンスされてから、約 1週間後 くらいにリリースされたようです。
AWS の Amazon EKS のドキュメントで eksctl のインストールの説明部分をみると、英語版の方では、バージョンの表示例が 1.0.9 になっていました。(2022年8月27日現在)
Installing or updating eksctl - Amazon EKS
If you have eksctl installed in the path of your device, the example output is as follows. If you want to update the version that you currently have installed with a later version, complete the next step, making sure to install the new version in the same location that your current version is in.
0.109.0
ただし、日本語の方では、バージョンの表示例は まだ 1.0.5 になっていました。(2022年8月27日現在)いずれ更新されると思います。
eksctl のインストールまたは更新 - Amazon EKS
eksctl がデバイスのパスにインストールされている場合、出力例は次のようになります。現在インストールされているバージョンを新しいバージョンで更新する場合は、次の手順を完了し、新しいバージョンを現在のバージョンと同じ場所にインストールするようにします。
0.105.0
ともあれ、eksctl で バージョン 1.23 の EKS クラスターを作成できるようになったのは、嬉しい事です。
早速、eksctl のバージョンを 1.109.0 にアップグレードして、EKSクラスター 1.23 の作成を試してみました。
$ eksctl version 0.109.0 $ eksctl create cluster \ > --name test123-cluster \ > --vpc-public-subnets subnet-0b10715b2edf27dde,subnet-023105dfe3f0a2bdb \ > --nodegroup-name test123-nodes \ > --node-type t3.small \ > --nodes 2 \ > --nodes-min 1 \ > --nodes-max 3 \ > --managed \ > --version 1.23 \ > --region ap-northeast-1 2022-08-26 13:15:16 [ℹ] eksctl version 0.109.0 2022-08-26 13:15:16 [ℹ] using region ap-northeast-1 2022-08-26 13:15:16 [ℹ] using existing VPC (vpc-0260526e8e00b9bb6) and subnets (private:map[] public:map[ap-northeast-1a:{subnet-0b10715b2edf27dde ap-northeast-1a 10.0.0.0/24 0} ap-northeast-1c:{subnet-023105dfe3f0a2bdb ap-northeast-1c 10.0.10.0/24 0}]) 2022-08-26 13:15:16 [!] custom VPC/subnets will be used; if resulting cluster doesn't function as expected,make sure to review the configuration of VPC/subnets 2022-08-26 13:15:16 [ℹ] nodegroup "test123-nodes" will use "" [AmazonLinux2/1.23] 2022-08-26 13:15:16 [ℹ] using Kubernetes version 1.23 2022-08-26 13:15:16 [ℹ] creating EKS cluster "test123-cluster" in "ap-northeast-1" region with managed nodes 2022-08-26 13:15:16 [ℹ] will create 2 separate CloudFormation stacks for cluster itself and the initial managed nodegroup 2022-08-26 13:15:16 [ℹ] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-northeast-1 --cluster=test123-cluster' 2022-08-26 13:15:16 [ℹ] Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "test123-cluster" in "ap-northeast-1" 2022-08-26 13:15:16 [ℹ] CloudWatch logging will not be enabled for cluster "test123-cluster" in "ap-northeast-1" 2022-08-26 13:15:16 [ℹ] you can enable it with 'eksctl utils update-cluster-logging --enable-types={SPECIFY-YOUR-LOG-TYPES-HERE (e.g. all)} --region=ap-northeast-1 --cluster=test123-cluster' 2022-08-26 13:15:16 [ℹ] 2 sequential tasks: { create cluster control plane "test123-cluster", 2 sequential sub-tasks: { wait for control plane to become ready, create managed nodegroup "test123-nodes", } } 2022-08-26 13:15:16 [ℹ] building cluster stack "eksctl-test123-cluster-cluster" 2022-08-26 13:15:16 [ℹ] deploying stack "eksctl-test123-cluster-cluster" 2022-08-26 13:15:46 [ℹ] waiting for CloudFormation stack "eksctl-test123-cluster-cluster" (中略) 2022-08-26 13:29:18 [ℹ] building managed nodegroup stack "eksctl-test123-cluster-nodegroup-test123-nodes" 2022-08-26 13:29:18 [ℹ] deploying stack "eksctl-test123-cluster-nodegroup-test123-nodes" 2022-08-26 13:29:18 [ℹ] waiting for CloudFormation stack "eksctl-test123-cluster-nodegroup-test123-nodes" (中略) 2022-08-26 13:33:01 [ℹ] waiting for the control plane availability... 2022-08-26 13:33:03 [ℹ] saved kubeconfig as "/home/ssm-user/.kube/config" 2022-08-26 13:33:03 [ℹ] no tasks 2022-08-26 13:33:03 [ℹ] all EKS cluster resources for "test123-cluster" have been created 2022-08-26 13:33:03 [ℹ] nodegroup "test123-nodes" has 2 node(s) 2022-08-26 13:33:03 [ℹ] node "ip-10-0-0-138.ap-northeast-1.compute.internal" is ready 2022-08-26 13:33:03 [ℹ] node "ip-10-0-10-72.ap-northeast-1.compute.internal" is ready 2022-08-26 13:33:03 [ℹ] waiting for at least 1 node(s) to become ready in "test123-nodes" 2022-08-26 13:33:03 [ℹ] nodegroup "test123-nodes" has 2 node(s) 2022-08-26 13:33:03 [ℹ] node "ip-10-0-0-138.ap-northeast-1.compute.internal" is ready 2022-08-26 13:33:03 [ℹ] node "ip-10-0-10-72.ap-northeast-1.compute.internal" is ready 2022-08-26 13:33:05 [ℹ] kubectl command should work with "/home/ssm-user/.kube/config", try 'kubectl get nodes' 2022-08-26 13:33:05 [ℹ] EKS cluster "test123-cluster" in "ap-northeast-1" region is ready $
期待通り、問題なく作成できました!
EKS クラスターは、eksctl 以外でも、AWS マネジメントコンソール や AWS CLI でも作成できますが、私は、EKS クラスターを作成する場合は、eksctl を使う派ですので、ようやく バージョン1.23 を eksctl で作成することができた、と感じています。
Amazon EKS でサポートされる バージョンが追加されたとき、どれくらいのタイムラグで、そのバージョンに対応した eksctl がリリースされるのかは、今後も注目していきたいと思います。
AWS SAM における Lambda 関数のエイリアスとバージョンの重みづけについて
以前から、AWS SAM を使用して AWS Lambda 関数のエイリアスとバージョンの重みづけを設定したいなーと思ってました。
ただ、結論から言うと、AWS SAM 仕様では重みづけの設定する方法は無く、AWS CloudFormation のプロパティとして設定する必要があることがわかりました。
エイリアスやバージョンの発行、という観点だと、AWS SAM では、AutoPublishAlias というプロパティを使用できます。
このプロパティの指定だけで、AWS Lambda 関数のエイリアスと、それに関連付けられた AWS Lambda 関数のバージョンが自動的に発行されます。
AutoPublishAlias を指定している場合、SAM でスタックが作成、更新される都度に新しいバージョンが発行され、エイリアスの重みづけは常に 100% に設定されます。
AutoPublishAlias を指定したうえで、さらに DeploymentPreference というプロパティを指定すると、 新バージョンへの段階的な移行が可能になり、例えば Canary や Linear などの手法で、時間の経過とともに新バージョンに振り分けるトラフィック量を自動的に変更したり、CloudWatch Alarm と連動させて、デプロイをロールバックすることもできます。 docs.aws.amazon.com
この AutoPublishAlias と DeploymentPreference は、非常に強力かつ便利ではあるのですが、意外に単純なことができないことがわかりました。
それは、Canary や Linear などの手法ではなく、単に エイリアスと複数バージョンの重みづけを設定すること です。これができないのです。
例えば、次のような手順を AWS SAM AutoPublishAlias と DeploymentPreference を指定して 行うことはできません。
- AWS Lambda関数の バージョン 1を発行する。エイリアスと関連付けて重みづけは 100% とする。
- AWS Lambda関数のコードを更新して、バージョン 2を発行する。エイリアスで、バージョン 1 は90%、バージョン 2は 10%の重みづけにする。
- AWS Lambda関数の バージョン 2の、エイリアスて重みづけを 100% とする。
DeploymentPreference で Canary や Linear を指定するのも便利ですが、その場合は、あくまであらかじめ用意されている、Canary10Percent15Minutes や Linear10PercentEvery10Minutes というタイプから選ぶしかありません。
トラフィックを移行する割合を手動で指定したい、自分でトラフィックを切り替えるタイミングを制御したいという場合は、AWS SAM 仕様のプロパティでは対応するものが無いのです。
では、どうすればいいかというと、AWS CloudFormation のプロパティで指定する、という方法があります。
まず、AWS Lambda 関数の バージョン 1を発行し、エイリアスと関連付けて重みづけは 100% とするための SAM テンプレートの例をみてみましょう。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: FunctionName: HelloSAMAliasVersion CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 HelloWorldFunctionVersion1: Type: AWS::Lambda::Version Properties: FunctionName: !Ref HelloWorldFunction Description: v1 HelloWorldFunctionAlias: Type: AWS::Lambda::Alias Properties: FunctionName: !Ref HelloWorldFunction FunctionVersion: !GetAtt HelloWorldFunctionVersion1.Version Name: live
SAM テンプレートとして記載していますが、AWS Lambda 関数のエイリアスやバージョンを発行する指定は、Type: AWS::Lambda::Version や Type: AWS::Lambda::Alias と、AWS CloudFormation のプロパティを指定しています。
このSAM テンプレートを使用して デプロイし、スタックを作成すると、エイリアス名 live で、最初のバージョンが重みづけ 100% で設定された状態になります。
次に、AWS Lambda 関数のコードを更新し、新しいバージョン 2として、エイリアス live に 10% の重みづけでトラフィックを振り分けたいとします。
その場合は、SAM テンプレートを次のように変更してデプロイします。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: FunctionName: HelloSAMAliasVersion CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 HelloWorldFunctionVersion1: Type: AWS::Lambda::Version Properties: FunctionName: !Ref HelloWorldFunction Description: v1 HelloWorldFunctionVersion2: Type: AWS::Lambda::Version Properties: FunctionName: !Ref HelloWorldFunction Description: v2 HelloWorldFunctionAlias: Type: AWS::Lambda::Alias Properties: FunctionName: !Ref HelloWorldFunction FunctionVersion: !GetAtt HelloWorldFunctionVersion1.Version Name: live RoutingConfig: AdditionalVersionWeights: - FunctionVersion: !GetAtt HelloWorldFunctionVersion2.Version FunctionWeight: 0.1
デプロイが完了すると、バージョン 1が 90%、バージョン 2が 10% になったことを確認できます。
この後、バージョン 2 へ完全に切り替えたい場合は、このテンプレートの FunctionWeight: で指定する値を 1.0 変更してデプロイします。
これらの プロパティについては、次のドキュメントも参考にしてください。
AWS CloudFormation のプロパティを使うと、自分で重みづけや、切り替えタイミングを制御できるのはいいのですが、プロパティの記載量はどうしても増えます。
SAM であれば、次のように、AWS Lambda 関数 で AutoPublishAlias を指定しつつ、さらに API Gateway の APIとの統合もシンプルに指定できます。
HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 AutoPublishAlias: live Events: HelloWorld: Type: Api Properties: Path: /hello Method: get
ただし、AWS CloudFormation のプロパティでエイリアスやバージョンを手動指定すると、このような書き方はできません。
なので、AutoPublishAlias で、自分でバージョンの重みづけができればいいのですが、それは現状ではサポートされていないようです。
(次の issue にも Feature request として挙げられていましたが、DeploymentPreferences を使いなさい、と close されてました。)
ちょっと残念ですね。
AWS SAM Accelerate と POSTMAN を使って AWS Lambda の Function URLs を手早く試す
AWS Lambda の Function URLs で、Auth タイプに AWS_IAM を指定した場合のアクセスを試そうと考えていたところ、AWS SAM Accelerate と POSTMAN を使えば、手早く試せるのではと思い立ったので、やってみました。
AWS Lambda の Function URLs については、次の AWS Blog の記事を参照してください。
また、AWS SAM Accelerate については、次の AWS Blog の記事を参照してください。
まず、SAM CLI が使用できる環境を用意します。
今回は SAM Accelerate を使うので、バージョン 1.34 以上が必要です。
SAM CLI のバージョンを確認します。
sam --version
1.34.1以上のバージョンでなければ、アップグレードします。
まず最新版をダウンロードします。
wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
次にインストールします。
sudo ./sam-installation/install --update
再び SAM CLI のバージョンを確認します。
sam --version
次のように、1.34 以降のバージョンになったので、大丈夫ですね。
SAM CLI, version 1.53.0
では、SAM の初期化を行います。
今回は、Python の Lambda 関数を作成します。また、ここでは Cloud 9 を使っているため、Pythonのバージョンを敢えて3.7 にしています。
sam init --app-template hello-world --name sam-tutorial --package-type Zip --runtime python3.7
あっという間に、SAM のリソースが用意されました。
今回は、Function URLs でのアクセスを試したいだけなので、Lambda 関数のコードは編集せず、Hello World のレベルのままにしておきます。
編集が必要なのは、template.yaml です。これを次のように書き換えます。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 FunctionUrlConfig: AuthType: AWS_IAM Outputs: HelloWorldFunctionEndpoint: Description: "HelloWorldFunction Function URL Endpoint" Value: Fn::GetAtt: HelloWorldFunctionUrl.FunctionUrl
Lambda 関数のプロパティで FunctionUrlConfig を指定しています。
また、Outputs セクションで、Function URLs のエンドポイントを出力するように指定しています。
このとき、属性名として、 <Lambda関数のリソース名>に Url.FunctionUrl をつけます。
これで、SAM のテンプレートは完成です。ではリソースを作成します。
cd sam-app sam sync --stack-name sam-app
SAM Accelerate の sync を使っているので、SAM の build や package、deploy を行う必要がありません。
次のように確認を求められたら、Y で応答します。
Enter Y to proceed with the command, or enter N to cancel: [Y/n]: Y
スタックが作成され、Output セクションで指定したエンドポイントが表示されます。
-------------------- Key HelloWorldFunctionEndpoint Description HelloWorldFunction Function URL Endpoint Value https://nbuyqvkie2c64v7mjdt7sni3qy0lbgym.lambda-url.ap-northeast-1.on.aws/
Function URLs の Auth タイプが NONE であれば、単純にこのエンドポイントにアクセスするだけでよいのですが、今回は Auth タイプは AWS_IAM なので、アクセスキー ID やシークレットアクセスキーをもとに作成した署名 (AWS の署名v4) が必要です。
AWS の署名v4 を作成する方法はいくつかありますが、今回は POSTMAN を使ってみます。
POSTMAN は、RESTful API を発行するときに、AWS の 署名v4 を自動生成する機能を提供しています。
次の図のように、指定して下さい。
Service Name に lambda と入力するのを忘れないようにしましょう。
POSTMAN で Send ボタンを選択して、 Function URL のエンドポイントにリクエストを発行すると、次のようなレスポンスが返ってきます。
正常にアクセスできましたね。
試しに、正しくないアクセスキー ID を指定してみると、ステータスコード 403で 次のようなメッセージが返されます。
{ "message": "The security token included in the request is invalid." }
では最後に、作成した Lambda 関数を削除します。
これも、 SAM CLI から削除できます。確認を求められたら、 y で応答します。
sam delete --stack-name sam-app Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y Do you want to delete the template file a19a97a7b854a2609df1ae91982ee843.template in S3? [y/N]: y
以上です!
Lambda 関数の Function URLs を試すだけであれば、マネジメントコンソールから手作業で作成してもいいのですが、デモ環境として再利用することも考慮し、今回は SAM を使ってみました。
ただし、SAM においても、package や deploy で多くのパラメータを指定するような操作はしたくなかったので、SAM Accelerate を使いました。
また、AWS の 署名v4 の生成には、POSTMAN を活用しました。
うまくツールを活用することで、あまり時間をかけず効率的に動作検証できますね。(横着ともいわれそうですが...)
AWS CloudFormation でスタック作成時 Rate exceeded が出て困った話
先日、Cloud9 の環境を複数作成する必要があったので、AWS CloudFormation のテンプレートを作成してスタックを作成しました。
次のテンプレートはあくまで抜粋ですが、実際使ったテンプレートでは 13 個もの AWS Cloud9 の環境を作成しました。
Cloud901: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box01 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User01.Arn Cloud902: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box02 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User02.Arn Cloud903: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box03 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User03.Arn
テンプレート作成後、テストでスタック作成行い、問題がない事を確認したのですが、いざ本番環境で必要な時にスタックを作成してみると、Rate exceeded エラーが出てスタック作成に失敗してしまい、大いに慌ててしまうことになりました。
AWS CloudFormation を使用して多くのリソースを作成時に Rate exceeded エラーが出ることは確かにありうることで、次のドキュメントにも記載があります。
このドキュメントにはいくつかの対処策が記載されていますが、今回は DependsOn 属性を使うことで対処しました。
DependsOn 属性は、本来はリソース間の依存性を考慮し、リソース作成の順番を制御するためのものですが、これを活用すれば スタック作成時に、一気にリソース作成の API を発行せず、順番に作成を行うことで、スロットリングによるRate exceeded エラーを回避できそうです。
また、この方法であればテンプレートの記述の変更だけで対処できます。
まずは、1つ1つ順番に作成するように記載してみました。
Cloud901: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box01 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User01.Arn Cloud902: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box02 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User02.Arn DependsOn: Cloud901 Cloud903: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box03 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User03.Arn DependsOn: Cloud902
これにより、Cloud9 の作成は完全に1つづつ行われるので、スロットリングによるRate exceeded エラーは確実に回避できそうです。
しかし、1つづつしか作成できないため、スタック作成が完了するまで時間もかかります。DependsOn 属性はスタック作成時だけでなく、削除時もその順番が考慮されるため、削除も1つづつ行われ、かなり時間がかかってしまいました。
私がテストしたところ、13個の Cloud9 の環境を作成するのに約14分、削除するのに 約20分かかりました。
そこで、DependsOn 属性の指定方法を次のように変更しました。
Cloud901: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box01 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User01.Arn Cloud902: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box02 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User02.Arn Cloud903: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: Cloud9box03 ImageId: amazonlinux-2-x86_64 InstanceType: t3.small OwnerArn: !GetAtt User03.Arn DependsOn: Cloud902
要するに、同時に2つづつ作成するように、DependsOn 属性の指定の方法を変えました。
こうすることで、スタック作成の時間は約 7分、削除の時間は約 9分に短縮することができ、現実的な運用として使用できることになりました。
時間短縮を目的に同時並行で作成する数を増やしていくと、またスロットリングによるRate exceeded エラーを引き起こす可能性があるため、同時並行作成数の決定には注意する必要がありますね。
また、並行して CloudTrail で証跡を S3 バケットに保存し、スロットリングのエラー発生後、その API コールの情報を Athenaで検索できるようにしました。機会があれば、その辺りについても、記事にしたいと思います。
AWS SAM を使用するための IAM ポリシー
AWS SAM (Serverless Application Model) を使用すると、AWS Lambda などを使用したサーバーレスアプリケーションのテストやデプロイで、様々な便利な機能を使用できます。
今回は、この AWS SAM を使用するために必要な IAM ポリシーについて考えてみます。
どのような IAM ポリシーが必要でしょうか?
もちろん、構築するアプリケーション内容に依存するのですが、AWS のドキュメントにヒントが記載されています。
このドキュメントでは、非常にシンプルな Hello World レベルのアプリケーションだと、以下のポリシーがあれば十分だと記載されています。
- AWSCloudFormationFullAccess
- IAMFullAccess
- AWSLambda_FullAccess
- AmazonAPIGatewayAdministrator
- AmazonS3FullAccess
- AmazonEC2ContainerRegistryFullAccess
ここでいう、Hello World のアプリケーションというのは、hello world という簡単なメッセージを返す Lambda 関数を、Amazon API Gateway のREST API から呼び出せるようにしているアプリケーションの事です。
さらに、このドキュメントには、Hello World アプリケーションに対して、きめ細かくポリシーを指定した場合の例も掲載されています。
ドキュメントの例
{ "Version": "2012-10-17", "Statement": [ { "Sid": "CloudFormationTemplate", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet" ], "Resource": [ "arn:aws:cloudformation:*:aws:transform/Serverless-2016-10-31" ] }, { "Sid": "CloudFormationStack", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet", "cloudformation:CreateStack", "cloudformation:DeleteStack", "cloudformation:DescribeChangeSet", "cloudformation:DescribeStackEvents", "cloudformation:DescribeStacks", "cloudformation:ExecuteChangeSet", "cloudformation:GetTemplateSummary", "cloudformation:ListStackResources", "cloudformation:UpdateStack" ], "Resource": [ "arn:aws:cloudformation:*:111122223333:stack/*" ] }, { "Sid": "S3", "Effect": "Allow", "Action": [ "s3:CreateBucket", "s3:GetObject", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::*/*" ] }, { "Sid": "ECRRepository", "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:CompleteLayerUpload", "ecr:CreateRepository", "ecr:DeleteRepository", "ecr:DescribeImages", "ecr:DescribeRepositories", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:InitiateLayerUpload", "ecr:ListImages", "ecr:PutImage", "ecr:SetRepositoryPolicy", "ecr:UploadLayerPart" ], "Resource": [ "arn:aws:ecr:*:111122223333:repository/*" ] }, { "Sid": "ECRAuthToken", "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken" ], "Resource": [ "*" ] }, { "Sid": "Lambda", "Effect": "Allow", "Action": [ "lambda:AddPermission", "lambda:CreateFunction", "lambda:DeleteFunction", "lambda:GetFunction", "lambda:GetFunctionConfiguration", "lambda:ListTags", "lambda:RemovePermission", "lambda:TagResource", "lambda:UntagResource", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration" ], "Resource": [ "arn:aws:lambda:*:111122223333:function:*" ] }, { "Sid": "IAM", "Effect": "Allow", "Action": [ "iam:CreateRole", "iam:AttachRolePolicy", "iam:DeleteRole", "iam:DetachRolePolicy", "iam:GetRole", "iam:TagRole" ], "Resource": [ "arn:aws:iam::111122223333:role/*" ] }, { "Sid": "IAMPassRole", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "*", "Condition": { "StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" } } }, { "Sid": "APIGateway", "Effect": "Allow", "Action": [ "apigateway:DELETE", "apigateway:GET", "apigateway:PATCH", "apigateway:POST", "apigateway:PUT" ], "Resource": [ "arn:aws:apigateway:*::*" ] } ] }
ただし、結論からすると、このドキュメントの例のポリシーは、AWS SAM で Hello World レベルのアプリケーションを作成、更新、削除するには不十分です
例えば、AWS SAM で作成したアプリケーションは、 sam delete
というコマンドで削除できますが、ドキュメントの例のポリシーでは、SAM のリソースを格納している S3 バケットからのオブジェクトの削除権限と、CloudFormation の操作である cloudformation:GetTemplate
を実行する権限が足りません。
また、この AWS SAM アプリケーションを sam deploy --guided
でデプロイする場合にも追加の考慮が必要です。
もし、sam deploy --guided
の実行が、そのリージョンにおいて初めての場合、自動的に CloudFormation で aws-sam-cli-managed-default という名前のスタックが構築され、 SAM 用の S3 バケットが作成されますが、ドキュメントの例だと、その作成権限も足りません。
よって、(ドキュメントの冒頭にも記載はありましたが) S3の権限においては AmazonS3FullAccessポリシー またはそれに相当する権限を付与しておかないと、SAM アプリケーションのデプロイや削除が不意に失敗する可能性があります。
次に示すポリシーは、ドキュメントの例を変更したものです。
S3 の権限の範囲を広げており、cloudformation:GetTemplate
の操作も許可するよう追加しています。
(あくまで一つの例ですが、少なくとも Hello World レベルのアプリケーションの作成、削除は可能です。sam deploy --guided をリージョンで初めて実行する場合でも、権限不足でエラーにはなりません。)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "CloudFormationTemplate", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet" ], "Resource": [ "arn:aws:cloudformation:*:aws:transform/Serverless-2016-10-31" ] }, { "Sid": "CloudFormationStack", "Effect": "Allow", "Action": [ "cloudformation:CreateChangeSet", "cloudformation:CreateStack", "cloudformation:DeleteStack", "cloudformation:DescribeChangeSet", "cloudformation:DescribeStackEvents", "cloudformation:DescribeStacks", "cloudformation:ExecuteChangeSet", "cloudformation:GetTemplateSummary", "cloudformation:GetTemplate", "cloudformation:ListStackResources", "cloudformation:UpdateStack" ], "Resource": [ "arn:aws:cloudformation:*:111122223333:stack/*" ] }, { "Sid": "S3", "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "*" ] }, { "Sid": "ECRRepository", "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:CompleteLayerUpload", "ecr:CreateRepository", "ecr:DeleteRepository", "ecr:DescribeImages", "ecr:DescribeRepositories", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:InitiateLayerUpload", "ecr:ListImages", "ecr:PutImage", "ecr:SetRepositoryPolicy", "ecr:UploadLayerPart" ], "Resource": [ "arn:aws:ecr:*:111122223333:repository/*" ] }, { "Sid": "ECRAuthToken", "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken" ], "Resource": [ "*" ] }, { "Sid": "Lambda", "Effect": "Allow", "Action": [ "lambda:AddPermission", "lambda:CreateFunction", "lambda:DeleteFunction", "lambda:GetFunction", "lambda:GetFunctionConfiguration", "lambda:ListTags", "lambda:RemovePermission", "lambda:TagResource", "lambda:UntagResource", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration" ], "Resource": [ "arn:aws:lambda:*:111122223333:function:*" ] }, { "Sid": "IAM", "Effect": "Allow", "Action": [ "iam:CreateRole", "iam:AttachRolePolicy", "iam:DeleteRole", "iam:DetachRolePolicy", "iam:GetRole", "iam:TagRole" ], "Resource": [ "arn:aws:iam::111122223333:role/*" ] }, { "Sid": "IAMPassRole", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "*", "Condition": { "StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" } } }, { "Sid": "APIGateway", "Effect": "Allow", "Action": [ "apigateway:DELETE", "apigateway:GET", "apigateway:PATCH", "apigateway:POST", "apigateway:PUT" ], "Resource": [ "arn:aws:apigateway:*::*" ] } ] }
例えば、すでにそのリージョンに sam deploy --guided
によって SAM 用の S3 バケットが作成されている前提であれば、ポリシーで対象にしているリソースをそのバケットに限定することもできますので、使用する状況により、S3 バケットのポリシーで許可する範囲は絞りこむことをお薦めします。
どなたかの参考になれば幸いです!
Amazon Linux 2 に rbac-lookup をインストールする
Amazon Linux 2 に rbac-lookup をインストールする時に、やや試行錯誤が必要だったので正しくインストールする手順をメモしておきます。
rbac-lookupは、Kubernetes 環境の ロールやクラスターロールとバインドしているユーザーやサービスアカウントの情報をシンプルに表示してくれるコマンドラインツールです。
rbac-lookup.docs.fairwinds.com
rbac-lookup は、Linux で brew コマンドが使用できる環境であれば容易にインストールできるはずなのですが、Amazon Linux 2 ではデフォルトでは brewが使えません。
よって、まず brew が使用できるようにします。
(実は、ここが一番試行錯誤したところです。)
まず前提として、Kubernetes クラスタに接続できる Amazon Linux 2 の環境にログインします。
以降は、OSユーザーが ssm-user という前提でコマンドを記載します。
まず、Development Tools グループを指定して必要なパッケージ群をインストールします。
sudo yum groupinstall 'Development Tools' -y
次に、Linuxbrew をインストールします。
sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
途中で次のように表示されるので、Enter キーを押します。
Press RETURN/ENTER to continue or any other key to abort:
この後、少し時間がかかりますが、brew のインストールが完了しますので、PATH を通しておきましょう。
PATH を通すためのコマンドは、brew のインストール完了時にも表示されています。
次のコマンドは、OSユーザーが ssm-user であることを前提にしています。
echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/ssm-user/.bash_profile eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
念のため、brew doctor
を実行して brew が正しく使用できるか確認しておきましょう。
brew doctor
次のように表示されれば OK です。
Your system is ready to brew.
これでようやく、rbac-lookup をインストールできます。
brew install FairwindsOps/tap/rbac-lookup
インストール完了後、さっそく rbac-lookup を試してみましょう。
次のコマンドでは、Kubernetes のグループにバインドされているロールを表示します。
rbac-lookup -k group
結果の例です。
SUBJECT SCOPE ROLE eks:kube-proxy-windows cluster-wide ClusterRole/system:node-proxier system:authenticated cluster-wide ClusterRole/eks:podsecuritypolicy:privileged system:authenticated cluster-wide ClusterRole/system:basic-user system:authenticated cluster-wide ClusterRole/system:discovery system:authenticated cluster-wide ClusterRole/system:public-info-viewer system:bootstrappers cluster-wide ClusterRole/eks:node-bootstrapper system:masters cluster-wide ClusterRole/cluster-admin system:monitoring cluster-wide ClusterRole/system:monitoring system:node-proxier cluster-wide ClusterRole/system:node-proxier system:nodes cluster-wide ClusterRole/eks:node-bootstrapper system:serviceaccounts cluster-wide ClusterRole/system:service-account-issuer-discovery system:unauthenticated cluster-wide ClusterRole/system:public-info-viewer
無事に rbac-lookup を実行できましたね!
今回は、EC2 インスタンスに AWS Systems Manager のセッションマネージャーを使用してアクセスしたので、OS ユーザーは ssm-user となっています。
再度セッションマネージャーで接続した後は、rbac-lookup コマンドの PATH を通すために、.bash_profile の内容を反映させる必要があります。
これを手っ取り早く行うには、 sudo su - ssm-user
を実行するとよいでしょう。
rbac-lookup はすごく便利なのですが、如何せん、brew でのインストールが必要になります。
macOS 環境であれば簡単にインストールできるのですが、Amazon Linux 2 では、brew 自体のインストールが必要なため、少し手間取りました。
この記事がどなたかの参考になれば嬉しいです!
AWS Step Functions から Amazon ECS のタスクを実行する
今回は、AWS Step Functions で Amazon ECS のタスクを実行するシンプルなステートマシンを作成していきます。
すでに Fargate で動作可能な ECS クラスターや ECS タスク定義、 ECS タスク実行ロール、VPCのサブネットやセキュリティグループは用意している前提です。
ステートマシンで ECS クラスターやタスク定義の ARN の指定が必要になるので、メモしておきます。次に挙げているのは例です。
ECS クラスターの ARN
arn:aws:ecs:ap-northeast-1:000000000000:cluster/test-cluster
ECS タスク定義の ARN
arn:aws:ecs:ap-northeast-1:000000000000:task-definition/python-web-hello:1
事前に ECS クラスターでタスクが実行できることを確認しておきましょう。
確認ができたら、AWS Step Functions のステートマシンを作成していきます。
今回は Workflow Builder を使用して、標準タイプのステートマシンを作成します。
この図で示している③の API パラメータ で、Cluster に ECS クラスターの ARN を、TaskDefinition に ECS タスク定義の ARN を指定するわけですが、実際は、それらの指定だけでは動作しません。
次の例に示すように、タスクを動作させる Fargate の配置先となる VPC サブネットや、セキュリティグループの ID も必要です。
それらを指定するための NetworkConfiguration 部分は Workflow Studio ではデフォルトで生成されないので注意しましょう。
{ "LaunchType": "FARGATE", "Cluster": "arn:aws:ecs:ap-northeast-1:000000000000:cluster/test-cluster", "TaskDefinition": "arn:aws:ecs:ap-northeast-1:000000000000:task-definition/python-web-hello:1", "NetworkConfiguration": { "AwsvpcConfiguration": { "AssignPublicIp": "DISABLED", "SecurityGroups": [ "sg-0c0abc379ab3abfab" ], "Subnets": [ "subnet-0abc000ab00ab0", "subnet-1abc011ab10ab2", ] } } }
API パラメータが入力出来たら、 次へ ボタンを 2回選択します。
アクセス許可 セクションでは、新しいロールの作成 を選びます。
これは、「ステートマシンの定義と詳細設定に基づいて、Step Fucntionsが 新しいロールを作成」とあるので良さそうです。
しかし、実はそうではないのですが、敢えてこのまま続けます。
ステートマシンの作成を完了します。
その後、実行の開始 ボタンを選択して、ステートマシンを実行してみましょう。
ステートマシンの実行は失敗します!
RunTaskのステートの例外の情報を見てみましょう。
エラー ECS.AccessDeniedException 原因 User: arn:aws:sts::000000000000:assumed-role/StepFunctions-MyStateMachine-role-e4865d7b/CPOWNuVYmrftNqvlpPKDpWuiEvWJfAsi is not authorized to perform: iam:PassRole on resource: arn:aws:iam::000000000000:role/ecsTaskExecutionRole because no identity-based policy allows the iam:PassRole action (Service: AmazonECS; Status Code: 400; Error Code: AccessDeniedException; Request ID: acbdd742-e0b2-4b53-937b-68be10c7c864; Proxy: null)
ECSのタスク実行ロールを passRole するポリシーが許可されていないことが原因ですね。
ステートマシン作成時に、自動的に新しいロールを作る設定の説明では「ステートマシンの定義と詳細設定に基づいて、Step Fucntionsが 新しいロールを作成」と記載されていたのですが、ECSのタスク実行ロールの passRole を許可するポリシーは、作成されるロールに設定してくれないのです。
そのため、このエラーメッセージで表示されている IAMロールに対して、次のポリシーを追加で許可しましょう。 (AWS アカウントID部分は、環境に合わせて変更して下さい。)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "arn:aws:iam::000000000000:role/ecsTaskExecutionRole" } ] }
ポリシーを追加したら、再度ステートマシンを実行してみて下さい。
今度は、うまく動きましたね。
ECSのコンソールでも動作していることが確認できます。
成功を確認したら、ECSのコンソールからタスクを停止して下さい。(コストを考慮しての停止です。)
AWS Step Functions の ECS のタスクを実行するステートマシンを作成すること自体は非常に簡単に行えますが、IAMロールについては自動作成に頼るよりも、あらかじめ必要なIAMロールを作成しておく方が良さそうですね!