実践!AWS CDK #25 Session Manager で SSH 接続

題字・息子たち
2021.09.16

はじめに

AWS Systems Manager(SSM)の Session Manager を介した ローカルマシンから EC2 インスタンスへの SSH 接続方法をご紹介します。

EC2 のセキュリティグループでは SSH の 22 番ポートを開放する必要はありません。
ただし EC2 用のキーペアは作成する必要があります。

正直、CDK との関連はあまりないのですが備忘録的に本シリーズに組み込みたいと思います。

前回の記事はこちら。

AWS 構成図

現在の構成はこちらです。

1

SSM の Session Manager を利用して VPC 内の EC2 にアクセスします。

本記事をシリーズに組み込んだ理由の一つとして、現在の構成や設定では既に Session Manager が EC2 に接続可能な状態であるということが挙げられます。
Session Manager でハマった場合は、以下の記事を参考に設定を確認してみてください。

実装

キーペアを EC2 のプロパティに組み込む必要があるため、その部分だけ修正します。

まずは devio-stg-key-pair という名前のキーペアを作成します。
名前のみ指定し、その他の項目はデフォルト値で OK です。

2

3

作成と同時にキーファイル devio-stg-key-pair.pem がダウンロードされるので、保存しておきます。デフォルトの状態だと SSH セッション開始時に次のようなパーミッションエラーが発生するので chmod コマンドで権限を絞っておきましょう。

Warning: Permanently added 'i-0fbfdfdd68a4f79f5' (ECDSA) to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'devio-stg-key-pair.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "devio-stg-key-pair.pem": bad permissions
ec2-user@i-0fbfdfdd68a4f79f5: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

以下のコマンドを実行することでエラーは解消されます。

$ chmod 600 devio-stg-key-pair.pem

次に cdk.json に Context を追加します。キーペアが指定された場合はそれを EC2 に関連付け、指定されない場合は従来通りキーペア無しで構築するようにします。

cdk.json

{
  "app": "npx ts-node --prefer-ts-exts bin/devio.ts",
  "versionReporting": false,
  "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "@aws-cdk/core:enableStackNameDuplicates": "true",
    "aws-cdk:enableDiffNoFail": "true",
    "@aws-cdk/core:stackRelativeExports": "true",
    "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true,
    "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true,
    "@aws-cdk/aws-kms:defaultKeyPolicies": true,
    "@aws-cdk/aws-s3:grantWriteWithoutAcl": true,
    "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true,
    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
    "@aws-cdk/aws-efs:defaultEncryptionAtRest": true,
    "systemName": "devio",
    "envType": "stg",
    "keyName": ""
  }
}

EC2 クラスの変更は以下の通りです。

lib/resource/ec2.ts

~ 省略 ~

    private createInstance(scope: cdk.Construct, resourceInfo: ResourceInfo): CfnInstance {
        const instance = new CfnInstance(scope, resourceInfo.id, {
            availabilityZone: resourceInfo.availabilityZone,
            iamInstanceProfile: this.instanceProfileEc2.ref,
            imageId: Ec2.latestImageIdAmazonLinux2,
            instanceType: Ec2.instanceType,
            securityGroupIds: [this.securityGroupEc2.attrGroupId],
            subnetId: resourceInfo.subnetId(),
            tags: [{
                key: 'Name',
                value: this.createResourceName(scope, resourceInfo.resourceName)
            }],
            userData: fs.readFileSync(Ec2.userDataFilePath, 'base64')
        });

        const keyName = scope.node.tryGetContext('keyName');
        if (keyName) {
            instance.keyName = keyName;
        }

        return instance;
    }
}

Context のキー keyName に値が入っていればその値(キーペア名)を EC2 インスタンスに設定しています。

デプロイ時は次のように keyName を設定します。

$ cdk deploy --context keyName=devio-stg-key-pair

設定

AWS の公式ドキュメント に従い、設定を行います。

大前提として、SSM の Session Manager で EC2 インスタンスが表示されることを確認しておきましょう。

4

Session Manager プラグインのインストール

こちらも公式ドキュメントを参考に Session Manager プラグインをローカルマシンにインストールします。

以下は Mac における 2021/09 時点の方法です。正式なインストール手順は公式ドキュメントを参照してください。

インストーラーのダウンロード

$ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"

パッケージの解凍

$ unzip sessionmanager-bundle.zip

インストールコマンドの実行

$ sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin

正常にインストールされたことの確認

$ session-manager-plugin

The Session Manager plugin is installed successfully. Use the AWS CLI to start a session.

上記のメッセージが表示されれば OK です。

SSH 設定ファイルの更新

~/.ssh/config に以下を追加します。

# SSH over Session Manager
host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

特定のプロファイルを指定したい場合はここに書く必要があります。(後述の SSH コマンド実行時では NG)

# SSH over Session Manager
host i-* mi-*
    ~省略~ --parameters 'portNumber=%p' --profile cm-personal"

セッションの開始

SSH のセッションを開始するには次のフォーマットで SSH コマンドを実行します。

$ ssh -i /path/my-key-pair.pem username@instance-id

以下の設定で実際にローカルマシンからコマンドを実行してみます。

  • username: ec2-user
  • instance-id: i-0fbfdfdd68a4f79f5

5

無事、EC2 インスタンスにログインできました。

便利ですね。

こちらが対象のインスタンス情報です。

6

セキュリティグループは ALB からの 80 番ポートしか許可していません。

7

セキュリティも安心です。

GitHub

今回のソースコードは コチラ です。

おわりに

この機能を利用することで EC2 インスタンスに SSH 用のポートを開けることなく、ローカルマシンから SSH 接続ができるようになります。セキュリティも向上しますし、場合によっては踏み台サーバーが不要になりコスト削減ができるかもしれません。興味がある場合はお試しください。

リンク