【AWS】手を動かして学ぶAWS AWS CloudShell

## この記事で伝えたいこと（ポイント）

- AWS CloudShellについて説明しているよ
- AWS CloudShellがVPCに対応した話を書いているよ
- 実際に触って確認しているよ

## はじめに

この記事ではAWSが提供するAWS CloudShell（以下本文ではCloudShell）を学習していく内容となっています。
主な内容としては実践したときのメモを中心に書きます。（忘れやすいことなど）
誤りなどがあれば修正していく想定です。

今回はCloudShellの基礎と使い方を見ながらVPCに対応したCloudShellを検証します。

[参考：AWS CloudShell now supports Amazon Virtual Private Cloud (VPC)](https://aws.amazon.com/jp/about-aws/whats-new/2024/06/aws-cloudshell-amazon-virtual-private-cloud/)

## AWS CloudShellとは

簡単に説明するとブラウザベースで提供されるAWSのインターフェイスです。公式ドキュメントでは以下のように説明されています。

> AWS CloudShell はブラウザベースの事前認証済みシェルで、 から直接起動できます AWS Management Console。 AWS Management Console いくつかの異なる方法 CloudShell から に移動できます。詳細については、AWS CloudShellの開始方法を参照してください。

[参考: とは AWS CloudShell](https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/welcome.html)

AWSを操作するときに利用できるなんか便利な機能ということだけうっすらわかると思います。

### 補足：そもそもShellってなんですか

そもそもですが、Shell（シェル）とはなんでしょうか。

原始的な話をするとシェルというのはユーザーとコンピュータのオペレーティングシステム（OS）間のインターフェイスとして機能するプログラムです。
※なお、接続先をKernel（カーネル）と表現する場合もあります。

「え、ユーザーが操作しているものってOSじゃないの」とそう思ったかもしれません。
ユーザーから与えられる処理はOSの前にシェルが処理します。

また、シェルにはさまざまな種類がありますが、ここでは割愛します。

## ではAWS CloudShellのShellとは

では、CloudShellも同様にOSを操作するものなのでしょうか。これは半分正解です。
CloudShellはAWSとユーザーの操作を仲介するシェルであるため、OSまたはカーネルを操作するものではありません。

つまりは`仲介する`という言葉を`Shell`という言葉で表現しているということになります。

## AWS CloudShellでできること・できないこと

では、CloudShellでできることはなんでしょうか。公式ドキュメントでは以下のように記載されています。

> AWS CloudShell セッション用に作成されたシェルを使用すると、任意のコマンドラインシェルをシームレスに切り替えることができます。具体的には、Bash、 PowerShell、および Z shell。 また、プリインストールされたツールやユーティリティにもアクセスできます。これらには以下が含まれます。git, make, pip, sudo, tar, tmux, vim, wget および zip.

> シェル環境は、 などの主要な主要なソフトウェア言語をサポートするように事前設定されています。Node.js また、Python。 つまり、例えば、Node.js また、Python ランタイムインストールを最初に実行しないプロジェクト。 PowerShell ユーザーは を使用できます。.NET Core ランタイム。

> これらのファイルを によって管理されているリモートリポジトリ AWS CloudShell にプッシュする前に、 で作成またはアップロードされたファイルをローカルリポジトリにコミットできます AWS CodeCommit。

[参考: とは AWS CloudShell](https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/welcome.html)

CloudShellを使えば、おおむねやりたいことはできます。ただし、追加料金なしで利用できる範囲では1GBしか利用できないため、一時的に大きなデータを保存しておいて移行するなどの用途には不向きです。

[参考：永続的ストレージ](https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/limits.html#persistent-storage-limitations)

なお、ドキュメントにもありますが、Dockerの使用についても不向きである可能性が高いです。

[Docker の使用](https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/working-with-aws-cloudshell.html)

## VPCとつなげると何が良いのか

なんとなくわかってきたところでハンズオンしていきたいですが、最近になってVPCの対応が発表されました。

[参考：AWS CloudShell now supports Amazon Virtual Private Cloud (VPC)](https://aws.amazon.com/jp/about-aws/whats-new/2024/06/aws-cloudshell-amazon-virtual-private-cloud/)

そもそも「CloudShell起動時のネットワークはどうなっているんだ。シェルを解釈して実行しているということはそこにインスタンスがいるんじゃないか」など疑問に思ったと思います。

このアップデートはそういう疑問を解消しつつ、`プライベートにシェルを実行できるようになった`というものです。たとえば、`プライベートにEC2/ECSを起動してSSMのセッションマネージャーを起動する`ということができるようになります。

つまりは踏み台サーバ的な役割を果たせるということです。

## AWS CloudShellに触ってみる

### シェル環境を構築する

実際に触って確認してみましょう。まずはAWSマネジメントコンソールを開きます。
今回は東京リージョンで実際にやってみるため`Tokyo`の文字を確認しながら、ターミナルアイコンをクリックします。

![bedrock1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/4f8ee256-973d-8e66-22dd-3b489821a122.png)

すると画面をおおうようにプロンプトが立ち上がります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/81b83c68-2136-c4cc-1381-a61f4f5ddd6e.png)

### AWS CLIを実行してみる

ぱっと実行できて実行してもよいコマンドであれば、なんでもいいですが、今回はS3に関するコマンドとSTSに関するコマンドで試してみましょう。まずはS3でバケットの一覧を表示します。

```bash
aws s3 ls
```

次にSTSのコマンドを実行します。

```bash
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) && echo $AWS_ACCOUNT_ID
```

問題なく実行結果が表示されたでしょうか。STSを実行した場合は今ログインしているアカウントのアカウントIDが表示されるはずです。

無事に終わりましたらいったん、CloudShellを閉じます。

![スクリーンショット 2024-12-04 20.22.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/dcb0b594-dd21-11eb-bbdd-9b3bafa37f5e.png)

## AWS CloudShellに触ってみる（VPC）

次にパブリックIPが割り当てられていないEC2インスタンスをサブネット上に起動してCloudShellからアクセスします。

### 検証するにあたっての説明

環境構築で画面ぽちぽちが大変だと思うので今回はCloudFormationテンプレートを用意しました。

- [ec2.yaml](https://github.com/ymd65536/platform/blob/main/single_ec2_template/cfn/ec2.yaml)

このテンプレートを適用してEC2にアクセスします。

### CloudShell上にテンプレートを配置する

まずは先ほどと同様にターミナルアイコンをクリックしてCloudShellを起動します。

![bedrock1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/4f8ee256-973d-8e66-22dd-3b489821a122.png)

すると画面をおおうようにプロンプトが立ち上がります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/81b83c68-2136-c4cc-1381-a61f4f5ddd6e.png)

上記のテンプレートをCloudShell上にコピーします。さまざまな方法がありますが、ここではCloudShellの機能を使ってアップロードします。

`Actions`から`Upload file`を選択します。

![スクリーンショット 2024-12-04 20.42.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/1c1470f6-3066-5910-cf3c-951599aa5852.png)

先ほどの`ec2.yml`をアップロードします。アップロード後に緑のバーが画面に表示されます。

![スクリーンショット 2024-12-04 20.43.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/c8e2dbd0-44d3-66a1-08bc-37ced40c9fa1.png)

### テンプレートを適用する

テンプレートがアップロードされているかどうかを確認します。

```bash
ls -la ec2.yaml
```

実行結果

```text
[cloudshell-user@ip-10-132-80-26 ~]$ ls -la ec2.yaml
-rw-r--r--. 1 cloudshell-user cloudshell-user 2446 Dec  4 11:43 ec2.yaml
```

テンプレートがアップロードされていることを確認できたため、環境構築のために以下のコマンドを実行します。

```bash
aws cloudformation deploy --stack-name ec2 --template-file ./ec2.yaml --tags Name=qiita --capabilities CAPABILITY_NAMED_IAM
```

実行結果

```text
[cloudshell-user@ip-10-132-80-26 ~]$ aws cloudformation deploy --stack-name ec2 --template-file ./ec2.yaml --tags Name=qiita --capabilities CAPABILITY_NAMED_IAM

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - ec2
[cloudshell-user@ip-10-132-80-26 ~]$ 
```

問題なく作成できました。

### VPCなしのCloudShellで接続

まずは接続したいEC2を特定します。

```bash
export INSTANCE_ID=`aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query 'Reservations[*].Instances[*].[InstanceId]' --output text`
```

そのまま作成されたEC2にSSMで接続してみます。

```bash
aws ssm start-session --target $INSTANCE_ID
```

実行結果

```bash
[cloudshell-user@ip-10-132-80-26 ~]$ aws ssm start-session --target $INSTANCE_ID

Starting session with SessionId: {ID}
sh-5.2$ 
```

### VPCありの接続（CloudShell on VPC）

次にCloudShell on VPCを試してみましょう。まずは環境を作成します。
`+`をクリックします。

![スクリーンショット 2024-12-04 22.06.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/8df98b87-e162-3c2c-d823-fba1d691c833.png)

`Create VPC environment`をクリックします。

![スクリーンショット 2024-12-04 22.07.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527543/7620c90b-e095-fdcc-4790-cc2098fc3e03.png)

作成画面が表示されますので項目を埋めていきます。

|項目|値|
|:---|:---|
|Name|qiita|
|Virtual private cloud (VPC)|MyVPCのVPC ID|
|Subnet|MyPrivateSubnet|
|Security group|ec2-InstanceSecurityGroupA|

`Create`をクリックします。接続先のEC2を特定する場合ですが、先ほどは`aws ec2 describe-instances`を利用していました。

今回はインターネットに接続されていないプライベートのサブネットにCloudShellの環境を作成しているため、以下のコマンドは応答が返ってきません。

```bash
export INSTANCE_ID=`aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query 'Reservations[*].Instances[*].[InstanceId]' --output text`
```

インスタンスIDは別のCloudShellで特定するかインスタンスの一覧から取得しましょう。

インスタンスのIDが特定できたら同様にAWS CLIで接続します。

```bash
aws ssm start-session --target $INSTANCE_ID
```

実行結果

```bash
[cloudshell-user@ip-10-132-80-26 ~]$ aws ssm start-session --target $INSTANCE_ID

Starting session with SessionId: {ID}
sh-5.2$ 
```

SSMは問題なく接続できます。理由としてはエンドポイントが設定として存在しているためです。
この理屈で言うとS3やSTSのコマンドは通りません。

※お試し用にコマンドを記載しておきます。

```bash
aws s3 ls
```

```bash
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) && echo $AWS_ACCOUNT_ID
```

実行結果

```bash
sh-5.2$ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) && echo $AWS_ACCOUNT_ID

Connect timeout on endpoint URL: "https://sts.ap-northeast-1.amazonaws.com/"

```

## コマンドを問題なく通すにはどうしたらいいか

いくつか手段がありますが、すぐに思いつく方法としては以下の通りです。

- NATを設定/構築する
- VPCエンドポイントを作成する

あるいは同一ネットワーク内にパブリックなEC2をおいておき、ルートを切ってプライベートサブネットからアクセスするという方法があります。この場合だとEC2が2台必要になります。

使い方やコストに合わせて工夫していきましょう。

## まとめ

今回はAWS CloudShellの使い方を実際に触って確認しました。
「AWSの環境に少しだけ触れようかなくらいの用途であれば、AWS CloudShellで十分」という印象を受けました。
閉域アクセスで他のサービスと接続するときはVPCエンドポイントなどを設定して対応しましょう。

## おわり