CloudShellでIAMポリシー/IAMロールを削除しようとして詰まった話
はじめに
先日、以下のハンズオンを実施した。
Lambdaの使い方がよく分かっていないこともあり、関数の作成や呼び出しは手順通りマネジメントコンソールで実行。問題なく関数呼び出しが出来た。
手順の最後にチュートリアル環境の削除手順があり、これもマネコンでの作業手順が記載されているが、せっかく最近CloudShellを触ったので、せめて最後の削除だけはCloudShellで実行してみることにした。そうしたら、IAMポリシー/IAMロールの削除で思うようにいかなかった場面があったので、備忘として記載することにした。
IAMポリシー削除
まずは以下のWEBページでCLIの削除手順を軽く確認。
最初はポリシーのリストを確認するようなので、とりあえずやってみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam list-policies | grep AWSLambdaS3E* "PolicyName": "AWSLambdaS3ExecutionRole-50e074db-f735-45b9-867f-2f1ca04f5ce5", "Arn": "arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaS3ExecutionRole-50e074db-f735-45b9-867f-2f1ca04f5ce5", [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
表示されたので、消そうとしてみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam delete-policy \ > --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaS3ExecutionRole-50e074db-f735-45b9-867f-2f1ca04f5ce5 An error occurred (DeleteConflict) when calling the DeletePolicy operation: Cannot delete a policy attached to entities. [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
「エンティティにアタッチされているポリシーは削除できない」というエラーが出てしまった。
ただ、ハンズオンの手順だと、いきなりポリシーを削除することになっている。マネコンとCLIでは勝手が違うのだろうか。
試しにマネコン上での削除を試みる。
マネコンだとエンティティのデタッチを自動で実施してくれるのか。うーむ、マネコン、侮れん。
再度CloudShellに戻って、ポリシーに割り当たっているエンティティについて確認する。aws iam list-entities-for-policy --policy-arn
コマンドで、指定したIAMポリシーにアタッチされているエンティティのリストが表示される模様。想定では、ハンズオンで作成したIAMロールが表示されるはず。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam list-entities-for-policy \ > --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaS3ExecutionRole-50e074db-f735-45b9-867f-2f1ca04f5ce5 { "PolicyGroups": [], "PolicyUsers": [], "PolicyRoles": [ { "RoleName": "my-s3-function-role", "RoleId": "AROATO53NFKUGNFFORV4I" } ] } [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
想定通り表示された。今度はCLI上でデタッチをやってみる。デタッチについてはaws iam detach-role-policy
コマンドで、デタッチしたいロールと、現在アタッチされているポリシーを指定する模様。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam detach-role-policy \ > --role-name my-s3-function-role \ > --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaS3ExecutionRole-50e074db-f735-45b9-867f-2f1ca04f5ce5 [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
デタッチコマンドが通ったので、改めてエンティティのアタッチ状況を確認する。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam list-entities-for-policy --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaS3ExecutionRole-50e074db-f735-45b9-867f-2f1ca04f5ce5 { "PolicyGroups": [], "PolicyUsers": [], "PolicyRoles": [] } [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
デタッチされた模様。では、改めてポリシーを削除する。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam delete-policy --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaS3ExecutionRole-50e074db-f735-45b9-867f-2f1ca04f5ce5 [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
削除成功。
IAMロール削除
続いて、IAMロールを削除する。まずはコマンドを以下のWEBページで確認する。
とりあえず、ページに記載の通りにやってみる。aws iam list-roles
コマンドを実行したら、現在作成されているロールがJSON形式で全て表示された。よくページ見たら、「対象ロール名が分からない場合」と書いてあった。今回は必要なかったな。
気を取り直して、次のコマンドから実行する。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam list-instance-profiles-for-role --role-name my-s3-function-role { "InstanceProfiles": [] } [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam list-role-policies --role-name my-s3-function-role { "PolicyNames": [] } [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
特に何も割り当たっていないように見えるので、削除コマンドを実行する。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam delete-role --role-name my-s3-function-role An error occurred (DeleteConflict) when calling the DeleteRole operation: Cannot delete entity, must detach all policies first. [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
消せない。「ロールを消したきゃ、まずポリシーからデタッチしろ」とエラーが出た。なんでだ?
他のコマンドで改めてポリシーのアタッチ状況を確認してみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam list-attached-role-policies --role-name my-s3-function-role { "AttachedPolicies": [ { "PolicyName": "AWSLambdaBasicExecutionRole-b6e2f444-ac64-4852-8685-d03f9e4b131c", "PolicyArn": "arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaBasicExecutionRole-b6e2f444-ac64-4852-8685-d03f9e4b131c" } ] } [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
なんか割り当たってる!?状況がよく飲み込めていないが、とりあえずこれをデタッチして、再度削除を試みる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam detach-role-policy \ > --role-name my-s3-function-role \ > --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/service-role/AWSLambdaBasicExecutionRole-b6e2f444-ac64-4852-8685-d03f9e4b131c [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam list-attached-role-policies --role-name my-s3-function-role { "AttachedPolicies": [] } [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws iam delete-role --role-name my-s3-function-role [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
消せた。。いったい全体どういうことなのか。
改めて調べてみた
IAMポリシーには「管理ポリシー」と「インラインポリシー」があり、最初に実行したaws iam list-role-policies
はインスタンスポリシーの一覧を、後で実行したaws iam list-attached-role-policies
は管理ポリシーの一覧を表示するものらしい。
管理ポリシーとインラインポリシーの違いについては、ザックリいうと、複数のIAMアイデンティティ(ユーザー、グループ、ロール)に割り当て可能なものが管理ポリシーで、特定のIAMアイデンティティと完全に紐づけされるものがインラインポリシーらしい。IAMにおいては通常は管理ポリシーを利用するのがベストプラクティスな模様。インラインポリシーは、特定のアイデンティティにのみ適用したいポリシーがあり、他とポリシーを共有することによって意図せぬ変更が発生することを避けたいケースで使う。
なお、バケットポリシーのようなリソースベースのポリシーは、必ずインラインポリシーになる模様。
管理ポリシーとインラインポリシーの違いについては、以下のサイトを参考にした。
おわりに
最初はCloudShellで設定を削除するだけのつもりだったが、思いがけずポリシーの種類の勉強になった。実際に手を動かすと、「なんか上手くいかない → 色々調べる → 知らないまま使っていたものの仕組みが分かる」という学習効果が得られるので、今後も積極的に手を動かしていきたい。
JAWS-UG CLI専門支部 #179R AWS CLI環境入門(Cloud9)を噛みしめながら復習する(あとLinuxも)
はじめに
5/20(木)に「JAWS-UG CLI専門支部 #179R AWS CLI環境入門(Cloud9)」に参加した。
ハンズオン型の勉強会だったのだが、入門と言いながらかなりのボリュームで、当日はついていくのがやっと。内容をきちんと理解できたとはいえない状態なので、改めて噛みしめながら復習してみる。ついでにLinuxも久しぶりに触ったので、あわせて復習する。
当日のハンズオンではCloud9用のVPC/IAM/EC2インスタンスの構築等をCloudShellで実施したが、今回のブログでは、一番最初に実施したVPCの作成のみを取り上げる。
CloudShellの起動と環境確認
自分はAWS初心者のため、この勉強会で始めてCloudShellを触った。マネジメントコンソールのアイコンから起動できることも知らなかった。
これってどういう環境なんだ?と思ったら、Amazon Linux 2 上で動いている環境らしい。 ↓のブログで詳しく紹介されているので、後で詳しく読んでみようと思う。
とりあえず、自分も何となく環境確認してみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ uname -a Linux ip-10-xxx-xxx-xxx.ap-northeast-1.compute.internal 4.14.225-168.357.amzn2.x86_64 #1 SMP Mon Mar 15 18:00:02 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
unameコマンド打てた。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ who [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
whoを打ったが特に何も表示されず。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ printenv # 気になったものだけ記載 HOSTNAME= PWD=/home/cloudshell-user AWS_REGION=ap-northeast-1 HOME=/home/cloudshell-user
HOSTNAMEは空欄。ホームディレクトリは"/home/cloudshell-user"、リージョンは東京リージョンだった。 リージョンについては、CloudShellを立ち上げたリージョンが設定されるのかと思う。
とりあえず、環境確認はこのくらいにして、ハンズオンの復習に入る。
VPCの構築
この手順では、VPCをCloudShellから作成する。手順に入る前に、全体の流れを確認する。
先に項番3について触れておくと、VPCの作成には"aws ec2 create-vpc"コマンドを使う。加えて、今回はサブコマンドで"--cidr-block"と"--tag-specifications"を使用し、VPCアドレスレンジとタグを指定する。サブコマンドの引数には"10.0.0.0/16"等の値を直接指定する事も可能だが、今回のハンズオンでは変数に格納し、変数を指定するようにしている。そのため、まず変数の設定を先に実施する。
1. VPCタグ名、VPCアドレスレンジ用のシェル変数を設定
まずは変数の設定
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ EC2_VPC_TAG_NAME='handson-cloud9-vpc-repeat' [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ [cloudshell-user@ip-10-xxx-xxx-xxx ~]$ EC2_VPC_CIDR='10.10.0.0/16'
勉強会で作ったVPCが残っているので、VPCのタグ名は変更した。アドレスレンジは重複していても問題ないはずだが、何となく変更。
続いて変数の確認。ハンズオン手順書には無いが、Linuxの復習も兼ねてsetコマンド打ってみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ set | grep EC2_VPC* EC2_VPC_CIDR=10.10.0.0/16 EC2_VPC_TAG_NAME=handson-cloud9-vpc-repeat [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
ちゃんと表示された。 手順書の確認方法でも確認してみる。手順書の方法は下記。
cat << END
# 0. AWS_REGION:"ap-northeast-1" AWS_REGION="${AWS_REGION}"
# 1. EC2_VPC_TAG_NAME:"handson-cloud9-vpc" EC2_VPC_TAG_NAME="${EC2_VPC_TAG_NAME}"
# 2. EC2_VPC_CIDR:"10.0.0.0/16" EC2_VPC_CIDR="${EC2_VPC_CIDR}"
END
すっかり忘れていたが、"cat <<"の後の文字は終了指定文字なので、別にENDじゃなくても何でもいいのね。試しに違う文字でやってみる。大文字と小文字が区別されるのかも確かめてみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ cat << START > > # 0. AWS_REGION:"ap-northeast-1" > AWS_REGION="${AWS_REGION}" > > # 1. EC2_VPC_TAG_NAME:"handson-cloud9-vpc-repeat" > EC2_VPC_TAG_NAME="${EC2_VPC_TAG_NAME}" > # 2. EC2_VPC_CIDR:"10.10.0.0/16" > EC2_VPC_CIDR="${EC2_VPC_CIDR}" > > END > start > START # 0. AWS_REGION:"ap-northeast-1" AWS_REGION="ap-northeast-1" # 1. EC2_VPC_TAG_NAME:"handson-cloud9-vpc-repeat" EC2_VPC_TAG_NAME="handson-cloud9-vpc-repeat" # 2. EC2_VPC_CIDR:"10.10.0.0/16" EC2_VPC_CIDR="10.10.0.0/16" END start [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
問題なく表示されたし、大文字と小文字は区別されていた。最後の"START"は終了指定文字なので表示されず。
そういえば、変数の参照時に$
をつけるのは覚えていたが、{}
の意味を覚えておらず調べ直した。参照する変数を明確にする場合は変数を{}
で囲むのか。
色々と寄り道したけど、これでVPCタグ名、VPCアドレスレンジ用のシェル変数設定は終わり。
2. タグ文字列用のシェル変数を設定
続いてはタグ文字列用のシェル変数を設定。だがその前に、タグ文字列(--tag-specificationsの引数)がどのような指定方法なのか、awsコマンドのリファレンスで確認しておく。
上記ページによると、リソースタイプを文字列で、タグをキーと値から成るリストで記載する必要があるとのこと。具体的には以下のような形式。
ResourceType=string,Tags=[{Key=string,Value=string},{Key=string,Value=string}] ...
今回は、タグのキーは"NAME"とし、値は項番1で作成した変数"EC2_VPC_TAG_NAME"を指定する。また、変数の設定が成功したら、echoコマンドで変数の中身を表示する。(&&を使用する)
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ STRING_EC2_VPC_TAG="ResourceType=vpc,Tags=[{Key=Name,Value=${EC2_VPC_TAG_NAME}}]" \ > && echo ${STRING_EC2_VPC_TAG} ResourceType=vpc,Tags=[{Key=Name,Value=handson-cloud9-vpc-repeat}] [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
問題なく表示された。
そういえば、Linuxでコマンドを途中で改行する時の\
も随分久しぶりに使った。久しぶり過ぎて、無駄にビビったw
3. 設定した変数を使用してVPCを作成
いよいよVPCを作成する。上述した通り、"aws ec2 create-vpc"コマンドを使用する。成功するとJSON形式でVPC設定が出力される。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws ec2 create-vpc \ > --cidr-block ${EC2_VPC_CIDR} \ > --tag-specifications ${STRING_EC2_VPC_TAG} { "Vpc": { "CidrBlock": "10.10.0.0/16", "DhcpOptionsId": "dopt-xxxxxxxx", "State": "pending", "VpcId": "vpc-xxxxxxxxxxxxxxxxx", "OwnerId": "XXXXXXXXXXXX", "InstanceTenancy": "default", "Ipv6CidrBlockAssociationSet": [], "CidrBlockAssociationSet": [ { "AssociationId": "vpc-cidr-assoc-xxxxxxxx", "CidrBlock": "10.10.0.0/16", "CidrBlockState": { "State": "associated" } } ], "IsDefault": false, "Tags": [ { "Key": "Name", "Value": "handson-cloud9-vpc-repeat" } ] } } [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
問題なく作成された。
4. VPCが存在していることを確認
最後にVPCが存在していることを確認する。これもCloudShell上で実施する。手順書のコマンドは以下。
aws ec2 describe-vpcs \
--filters Name=tag:Name,Values=${EC2_VPC_TAG_NAME} \
--query 'Vpcs[].Tags[?Key == `Name`].Value' \
--output text
VPC設定を表示させたうえでフィルタしているのは何となく分かるが、正確な所は分からないので、コマンドリファレンスを調べてみる。
あれ、サブコマンドに--filtersはあるが、--queryと--outputが無い。
と思ったら、以下のURLに説明があった。
--queryと--outputは、特定のAWSコマンドのサブコマンドではなく、AWS CLI共通のフィルタ方式らしい。で、内容としては、--filterで対象のVPCを指定し、--queryで対象の設定値を指定し、--outputで出力形式を指定している、という事のようだった。
折角なのでフィルタせずに色々試してみる。まずは"aws ec2 describe-vpcs"コマンドだけ実施してみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws ec2 describe-vpcs { "Vpcs": [ { "CidrBlock": "10.0.0.0/16", "DhcpOptionsId": "dopt-xxxxxxxxxx", "State": "available", "VpcId": "vpc-xxxxxxxxxxxxxx", "OwnerId": "xxxxxxxxxxxx", "InstanceTenancy": "default", "CidrBlockAssociationSet": [ { "AssociationId": "vpc-cidr-assoc-xxxxxxxxxxx", "CidrBlock": "10.0.0.0/16", "CidrBlockState": { "State": "associated" } } ], "IsDefault": false, "Tags": [ { "Key": "Name", "Value": "handson-cloud9-vpc" } ] }, { "CidrBlock": "10.10.0.0/16", "DhcpOptionsId": "dopt-xxxxxxxx", "State": "available", "VpcId": "vpc-xxxxxxxxxxxx", "OwnerId": "xxxxxxxxxxxx", "InstanceTenancy": "default", "CidrBlockAssociationSet": [ { "AssociationId": "vpc-cidr-assoc-xxxxxxxxxx", "CidrBlock": "10.10.0.0/16", "CidrBlockState": { "State": "associated" } } ], "IsDefault": false, "Tags": [ { "Key": "Name", "Value": "handson-cloud9-vpc-repeat" } ] } ] }
続いて、--output textだけつけてみる。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws ec2 describe-vpcs \ > --output text VPCS 10.0.0.0/16 dopt-xxxxxx default False xxxxxxxxxxx available vpc-xxxxxxx CIDRBLOCKASSOCIATIONSET vpc-cidr-assoc-xxxxxxxxxxxx 10.0.0.0/16 CIDRBLOCKSTATE associated TAGS Name handson-cloud9-vpc VPCS 10.10.0.0/16 dopt-xxxxxxx default False xxxxxxxxxxx available vpc-xxxxxxx CIDRBLOCKASSOCIATIONSET vpc-cidr-assoc-xxxxxxxxxxxx 10.10.0.0/16 CIDRBLOCKSTATE associated TAGS Name handson-cloud9-vpc-repeat [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
値だけが出力された。コンパクトだけど見づらい。。
次は--filterと--outputをつける。↑の形式で、今回作ったVPCだけが表示されるはず。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws ec2 describe-vpcs \ > --filters Name=tag:Name,Values=${EC2_VPC_TAG_NAME} \ > --output text VPCS 10.10.0.0/16 dopt-xxxxxxx default False xxxxxxxxxxx available vpc-xxxxxxx CIDRBLOCKASSOCIATIONSET vpc-cidr-assoc-xxxxxxxxxxxx 10.10.0.0/16 CIDRBLOCKSTATE associated TAGS Name handson-cloud9-vpc-repeat [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
想定通りだった。
最後に--queryをつける。'Vpcs[].Tags[?Key == `Name`].Value'は、上記のJSONのフルパスを指定している。?Key == `Name`の部分は"タグのキーがNAMEのものだけを対象とする"という意味。
[cloudshell-user@ip-10-xxx-xxx-xxx ~]$ aws ec2 describe-vpcs \ > --filters Name=tag:Name,Values=${EC2_VPC_TAG_NAME} \ > --query 'Vpcs[].Tags[?Key == `Name`].Value' \ > --output text handson-cloud9-vpc-repeat [cloudshell-user@ip-10-xxx-xxx-xxx ~]$
これでこの手順は一通り完了。
おわりに
当日のハンズオンでは時間の都合もあり、ものの数分で完了させたが、改めてじっくりやってみると、たくさん学びがあった。この後の手順も復習したいと思う。(比較的似た手順が多いので、今後はブログでここまで長く書くことはないと思うが。。)