AWS アカウントから IAM の SSL サーバー証明書を撲滅した話

HTTPS でアクセス可能な API などの Web サービスを構築する場合、サーバー証明書が必要になります。

AWS の場合は現在は ACM (AWS Certificate Manager) を使うことで、自動更新される証明書を無料で発行できますので完全にそちらを使っているのですが、ACM 登場以前は他社から購入した証明書を AWS の IAM に登録してそれを利用しなければなりませんでした。 (EC2 で自前の Web サーバーを用意する場合は IAM に登録する必要はありませんが、ここではサービスのスケールアウトを考慮して CloudFront や ELB などを使う場合を想定しています。)

しかしたいていの証明書には有効期限というものがあり、しかしながら IAM に登録した証明書は ACM の証明書のように自動更新というわけにはいかないので、手動で更新していく必要があります。(更新するついでに ACM の証明書にしてしまうのがいいですね。)

IAM に登録した証明書は、CloudFront と Elastic Load Balancer (ELB) で利用可能ですが、たとえば API Gateway でカスタムドメインを使うと CloudFront 経由で証明書が利用できたり、Elastic Beanstalk も Load balancer を使う設定にしていると ELB 経由で証明書を利用する設定にできます。

私が把握しているのはこの 4 つのサービス(CloudFront、ELB、API Gateway、EB)のみですが、もしかしたら他にも IAM の証明書を使うことができるサービスがあるかもしれません。

さらに、一つのアカウントの中で複数のリージョンにまたがってそれらのサービスを使用して IAM の証明書を用いているという場合も考えられますし、場合によっては複数のアカウントを使いこなしているかもしれません。

そのような場合に、どこで IAM の証明書を使っているかをすべて手作業で列挙するのはなかなか難しいと思います。

そこでスクリプトを書いて aws コマンドを駆使して IAM の証明書を見つけ出してみました。

Detects if any IAM cert is used in the specified A ...

実行方法ですが、

$ ./iam-cert-check.sh <profile> ...

という具合に、aws コマンドで使うプロファイル名を指定します。(複数指定可能です)

これでいろいろな環境の IAM 証明書の使用の有無を一度にチェックできます。(もちろんそのプロファイルに十分な権限を与えておく必要はあります)

もしかしたらスクリプトにバグがあって IAM 証明書の存在を見逃している可能性も否定できませんので、ご利用は自己責任でお願いします。 また、今回チェック対象にした 4 つ以外のサービスでも IAM 証明書が使われている可能性がある場合はお知らせいただけると嬉しいです。

このスクリプトを利用して検出したすべての IAM の証明書を ACM の証明書に切り替えたら、あとは IAM の証明書を削除します。

aws iam delete-server-certificate --server-certificate-name <name> --profile <profile>

このコマンド、証明書をどこかで利用中でも容赦なく削除できてしまうそうなので十分な注意が必要です。 (AWS コマンドのリファレンスにその旨の警告があり、それで怖くなって調べていたらいつの間にか今回のスクリプトが出来上がっていましたw)

いったん ACM の証明書に切り替え終わると、後は条件を満たしていれば自動更新されるので安心ですね。

なお、ACM の証明書でも、自動更新の条件を満たしていない証明書があったときのことを考え、弊社では毎日一回 ACM の証明書の有効期限を自動でチェックして Slack に結果を通知しています。未使用の証明書などを削除するきっかけになるのでこれも役に立っています。 機会があればそちらのコード(Lambda 上で動く Go のプログラム)もご紹介しようかと思います。