AWS CloudFormationでEC2キーペアを作成する

AWS CloudFormationでEC2のキーペアを作成する方法についてまとめます。

従来はEC2のキーペアはCloudFormationでの作成ができなくて、例えばEC2インスタンス作成時には既存（別途作成済み）のキーペアを指定する必要がありました。しかし2022年4月29日のアップデートに、キーペアをCloudFormationテンプレートで作成できるとの一文がありました。

> In addition to this, customers can now also create and delete key pairs using CloudFormation templates. To learn more about key pairs visit our documentation.  
> ([AWS adds new management features for EC2 key pairs](https://aws.amazon.com/jp/about-aws/whats-new/2022/04/aws-management-features-ec2-key-pairs/))

しかしこのプレスリリースからのリンク先や、CloudFormationユーザーガイドの「EC2 キーペアを作成する」などを見ても、作成方法の説明はなさそうでした。

* [Amazon EC2 key pairs and Linux instances - Amazon Elastic Compute Cloud](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html)
* [Creating an EC2 key pair - AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-create-keypair.html)

そこでリソースドキュメントを確認し、実際に作成をしてみてこれができることを確認しました。

# ドキュメントの情報

CloudFormationのリソースのリファレンス「[AWS::EC2::KeyPair - AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-keypair.html)」を見つけることができました。以下ドキュメントから。

* テンプレートに `PublicKeyMaterial` プロパティを含めると、既存のキーペアがインポートされる。
* このプロパティを省略すると、Amazon EC2が新しいキーペアを作成し、プライベートキーをAWS Systems Managerパラメータストアに `PublicKeyMaterial/ec2/keypair/{key_pair_id}` の形式で保存する。

プロパティは以下。

|プロパティ名|必須|デフォルト値|説明|
|---|---|---|---|
|`KeyName`|yes||キーペアの名前|
|`KeyType`|no|`rsa`|キーペアの種類。`rsa` か `ed25519`（Windowsは未サポート）を指定。|
|`PublicKeyMaterial`|no||インポートする公開キーマテリアル。省略時は新しいキーペアが作成される。|
|`Tags`|no||タグ|

インスタンス起動時に新規キーペアを作成するテンプレート例（YAML形式）。

```yaml
Resources:
  NewKeyPair:
    Type: 'AWS::EC2::KeyPair'
    Properties:
      KeyName: MyKeyPair
  Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: ami-02b92c281a4d3dc79
      KeyName: !Ref NewKeyPair
```

<div style="page-break-before:always" />

# 試行

## CloudFormationでの作成

上記ドキュメントのコード例を少しだけいじって、試行用に以下のテンプレートを用意しました。リージョン不問で利用できるはず。

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: "ec2-with-new-keypair: keypair creation sample template"

Parameters:
  LinuxAMI:
    Type: AWS::SSM::Parameter::Value<String>
    Description: "No change required. This parameter will automatically converted to latest AMI ID."
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  NewKeyPair:
    Type: 'AWS::EC2::KeyPair'
    Properties:
      KeyName: KeyPair20220506
  Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !Ref LinuxAMI
      KeyName: !Ref NewKeyPair
```

このテンプレートでCloudFormationスタックの作成を行いました。まずイベントにはKeyPairの生成が記録されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/090925f3-46d5-3a80-7d0c-49fb1b565f79.png)

スタック作成完了後、リソースを確認すると作成された `AWS::EC2::KeyPair` がありました。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/6edd1ad9-73ed-2d39-ffc8-46ebd89b6492.png)

期待通りの動作をしています。

## 作成されたキーペアの確認

[EC2のキーペアの画面](https://ap-northeast-1.console.aws.amazon.com/ec2/v2/home#KeyPairs)で、このキーペアが存在することを確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/5e460b56-414f-0748-23c7-7f978c34bb99.png)

[Systems Managerのパラメータストア](https://ap-northeast-1.console.aws.amazon.com/systems-manager/parameters)を見ると `/ec2/keypair/key-xxxxx` が標準パラメータ（SecureString）として作成されたことが確認できました。 `key-xxxxx` の部分はキーペアのIDで、EC2のキーペアの画面で確認できます。

![](2022-05-06-17-16-31.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/d30dc310-163a-171d-1980-f37d75dd4d9a.png)

パラメータの詳細表示を見ると、SecureString（暗号化文字列）なので最初は値が表示されません。「表示」をクリックすると、値にプライベートキー文字列が格納されていることが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/32bea4e6-ede9-6e3c-575a-dfbe582a7d9d.png)

## CloudFormationでの削除

作成したCloudFormationスタックの削除を行いました。まずイベントにKeyPairの削除が記録されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/d952a979-1d1a-8891-fa54-0cd19f3d7859.png)

完了後、リソース状態は `DELETE_COMPLETE` になっていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55718/6299116c-4dc3-a044-fe85-b3e527993457.png)

実際に、以下の状態になっていることを確認できました。

* EC2のキーペア画面で、このキーペアが存在しなくなっている。
* パラメータストアで、プライベートキー文字列を格納したパラメータがなくなっている。

## 終わりに

* CloudFormationテンプレートにより、キーペアの作成ができるようになっていることを確認できました。
* キーペアのシークレットキーは、自動的にSystems Manager Parameter Storeに格納されました。
    * マネージメントコンソール（Web画面）でのキーペア作成時にはシークレットキーはキーペア作成完了時にダウンロードされますが、CloudFormationでの作成時にはここから取得することになります。
    * 標準パラメータなので、[Parameter Storeの料金](https://aws.amazon.com/jp/systems-manager/pricing/#Parameter_Store)は発生しないと思います。ただしSecureStringなので、シークレットキーが作成される際の暗号化とこれを取得するときの複合化に[KMSのキー使用料](https://aws.amazon.com/jp/kms/pricing/)が発生しそうな気がします（通常の使い方なら微々たるものでしょう）。
* キーペアはスタックのリソース表示には出てこないものの、スタックの一部になるようで、スタック削除時に一緒に削除されました。

「すぐにデプロイして使えるCloudFormationテンプレート」をつくろうとすると、EC2インスタンスも作成する場合はキーペアを事前に用意してもらい指定する必要があるなどといったことがちょっと厄介でしたが、これからはそうしたことなしにCloudFormationテンプレートでキーペアも生成できます。

# 参考

* [AWS adds new management features for EC2 key pairs](https://aws.amazon.com/jp/about-aws/whats-new/2022/04/aws-management-features-ec2-key-pairs/)
* [AWS::EC2::KeyPair - AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-keypair.html)
* [料金 - AWS Systems Manager | AWS](https://aws.amazon.com/jp/systems-manager/pricing/)
* [料金 - AWS Key Management Service | AWS](https://aws.amazon.com/jp/kms/pricing/)