CloudShell VPC environment から VPC内のEC2インスタンスやRDS DBインスタンスに接続してみた
もっと簡単にVPC内のリソースにアクセスしたい
こんにちは、のんピ(@non____97)です。
皆さんはもっと簡単にVPC内のリソースにアクセスしたいと思ったことはありますか? 私はあります。
VPC上のRDS DBインスタンスやRedisクラスターなどのリソースに接続したい場合、Site-to-Site VPNやClient VPN、Direct Connectがなければ踏み台が必要になります。
踏み台へのアクセス方法は以下のようなものがあります。
- 直接SSH
- SSMセッションマネージャー
- EC2 Instance Connect
SSMセッションマネージャーとEC2 Instance Connectについては以下記事をご覧ください。
しかし、上述のいずれのパターンもEC2インスタンスやECS Fargateなどの課金が発生するリソースをプロビジョニングする必要があります。
そんな時に便利なのはCloudShell VPC environmentです。
これにより、CloudShellからVPC内のリソースにより安価に接続することができそうです。実際に試してみました。
いきなりまとめ
- インターネットに出たりAWSのAPIを叩く要件がないのであれば、インターネットへルーティングさせる経路やVPCエンドポイントは存在しなくとも動作する
- 検証した限り、自動でVPCエンドポイントは作成されなかった
- CloudShell VPC environmentのENIでパブリックIPの自動割り当てを有効化してもパブリックIPアドレスは割り当てられない
- Elastic IPアドレスの割り当ては可能
- CloudShell VPC environmentからVPC内のEC2インスタンスやRDS DBインスタンスに問題なく接続できる
- デフォルトで
psql
やmariadb
コマンドはインストールされている
- デフォルトで
- dnfのリポジトリにアクセスするためにはインターネットへの経路が必要
- 永続ストレージはサポートされていないため、一時的な検証用途で使うのが良さそう
やってみた
検証環境
検証環境は以下のとおりです。
疎通確認用にEC2インスタンスと、RDS DBインスタンスを用意しました。
CloudShell VPC environmentの作成
まず、CloudShell VPC environmentを作成します。
20秒ほどで作成は完了しました。
CloudTrailに記録されたイベントは以下のとおりです。指定したVPCやサブネット、セキュリティグループがイベントに含まれていますね。
{
"eventVersion": "1.09",
"userIdentity": {
"type": "AssumedRole",
"principalId": "AROA6KUFAVPUZTMI6DMFH:<IAMユーザー名>",
"arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<IAMロール名>/<IAMユーザー名>",
"accountId": "<AWSアカウントID>",
"accessKeyId": "<accessKeyId>",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "<principalId>",
"arn": "arn:aws:iam::<AWSアカウントID>:role/<IAMロール名>",
"accountId": "<AWSアカウントID>",
"userName": "<IAMユーザー名>"
},
"attributes": {
"creationDate": "2024-06-18T07:01:59Z",
"mfaAuthenticated": "true"
}
}
},
"eventTime": "2024-06-18T07:31:37Z",
"eventSource": "cloudshell.amazonaws.com",
"eventName": "CreateEnvironment",
"awsRegion": "ap-northeast-1",
"sourceIPAddress": "<操作端末のIPアドレス>",
"userAgent": "<ユーザーエージェント>",
"requestParameters": {
"EnvironmentName": "non-97-test-cloudshell",
"VpcConfig": {
"VpcId": "vpc-081ab1b7c99573078",
"SecurityGroupIds": [
"sg-0091d76056a2ef6d0"
],
"SubnetIds": [
"subnet-0d4be822a6d6571c2"
]
}
},
"responseElements": {
"Status": "CREATING",
"StartScreenMessages": [],
"EnvironmentId": "8cdd826d-3087-48d1-a90a-f746894d2242"
},
"requestID": "71aa06cf-7ab0-4c31-bb86-67bb55041320",
"eventID": "f6b1c948-a198-48d8-9a6d-3e533bf03be0",
"readOnly": false,
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "<AWSアカウントID>",
"eventCategory": "Management"
}
CloudShell VPC environmentをユーザーに作成させたくない場合は、以下の条件キーを使用することで制御可能です。
CloudShell:VpcIds
: 1つ以上のVPCを許可または拒否するCloudShell:SubnetIds
: 1つ以上のサブネットを許可または拒否するCloudShell:SecurityGroupIds
: 1つ以上のセキュリティグループを許可または拒否する
詳細は以下AWS公式ドキュメントをご覧ください。
また、気になるVPCエンドポイントですが、作成して1時間ほど経過しても作成はされていません。S3のゲートウェイ型VPCエンドポイントはVPC作成時に併せて作成したものです。
AWS公式ドキュメントにはAWS may provision network access to the following services for the underlying compute host
と記載がありました。
To provide a managed CloudShell environment for your account, AWS may provision network access to the following services for the underlying compute host:
- Amazon S3
- VPC endpoints
- com.amazonaws.<region>.ssmmessages
- com.amazonaws.<region>.logs
- com.amazonaws.<region>.kms
- com.amazonaws.<region>.execute-api
- com.amazonaws.<region>.ecs-telemetry
- com.amazonaws.<region>.ecs-agent
- com.amazonaws.<region>.ecs
- com.amazonaws.<region>.ecr.dkr
- com.amazonaws.<region>.ecr.api
- com.amazonaws.<region>.codecatalyst.packages
- com.amazonaws.<region>.codecatalyst.git
- aws.api.global.codecatalyst
You cannot restrict access to these endpoints by modifying your VPC configuration.
「これはカスタマーVPC上にVPCエンドポイントが作成される場合がある」なのか「AWS管理のVPC上にVPCエンドポイントが作成される場合がある」のどちらの意味なのかは読み取れませんでした。個人的にはunderlying compute host
とあるので、後者のような気がしています。
作成したCloudShell VPC environmentの状態の確認
起動完了後のCloudShellの状態を確認します。
CloudShell上で実行できるコマンドは以下のとおりです。
CloudShell上で実行できるコマンド (長いので折りたたみ)
$ for x in ${PATH//:/ }; do ls -1 $x; done | sort | uniq
ls: cannot access '/home/cloudshell-user/.local/bin': No such file or directory
ls: cannot access '/home/cloudshell-user/bin': No such file or directory
[
accessdb
addpart
adduser
agetty
alias
alternatives
apropos
apropos.man-db
arch
arp
arpd
arping
arptables
arptables-nft
arptables-nft-restore
arptables-nft-save
arptables-restore
arptables-save
awk
aws
aws_completer
b2sum
base32
base64
basename
basenc
bash
bashbug
bashbug-64
bg
blkdeactivate
blkdiscard
blkid
blkzone
blockdev
bridge
busctl
cal
ca-legacy
capsh
captoinfo
cat
catchsegv
catman
cd
cdk
cdk.d.ts
cdk.js
cfdisk
cfn-lint
chacl
chage
chardetect
chcon
chcpu
chevron
chgpasswd
chgrp
chmem
chmod
choom
chown
chpasswd
chroot
chrt
cksum
clear
clock
clockdiff
clusterdb
cmp
col
colcrt
colrm
column
comm
command
containerd
containerd-shim
containerd-shim-runc-v1
containerd-shim-runc-v2
cookiecutter
copilot
coreutils
cp
cracklib-check
cracklib-format
cracklib-packer
cracklib-unpacker
create-cracklib-dict
createdb
createuser
csplit
ctr
ctrlaltdel
ctstat
curl
cut
cvtsudoers
cyrusbdb2current
date
dateparser-download
dbus-broker
dbus-broker-launch
dd
debuginfod-find
delpart
devlink
df
diff
diff3
dir
dircolors
dirname
dmesg
dmfilemapd
dmsetup
dmstats
dnf
dnf-3
docker
docker-containerd
docker-containerd-shim
docker-ctr
dockerd
docker-init
docker-proxy
docker-runc
dropdb
dropuser
du
eb
ebtables
ebtables-nft
ebtables-nft-restore
ebtables-nft-save
ebtables-restore
ebtables-save
echo
ecs-cli
egrep
eject
encguess
env
eqn
ether-wake
expand
expr
factor
faillock
fallocate
false
fc
fdformat
fdisk
fg
fgrep
fincore
find
findfs
findmnt
flask
flock
fmt
fold
free
fsck
fsck.cramfs
fsck.minix
fsck.xfs
fsfreeze
fstrim
funzip
fuser
gapplication
gawk
gdbus
gencat
genl
geqn
getcap
getconf
getent
getfacl
getopt
getopts
getpcaps
gio
gio-querymodules-64
git
git-receive-pack
git-remote-codecommit
git-shell
git-upload-archive
git-upload-pack
glib-compile-schemas
gmake
gneqn
gnroff
gpasswd
gpg
gpg2
gpg-error
gpgme-json
gpgv2
gpic
grep
groff
grops
grotty
groupadd
groupdel
groupmems
groupmod
groups
grpck
grpconv
grpunconv
gsettings
gsoelim
gtar
gtbl
gtroff
guild2.2
guile2.2
guile-tools2.2
gunzip
gzexe
gzip
halt
hardlink
hash
head
hexdump
homectl
hostid
hostnamectl
hwclock
i386
iconv
iconvconfig
id
ifcfg
ifconfig
ifenslave
ifstat
infocmp
infotocap
init
install
ionice
ip
ip6tables
ip6tables-legacy
ip6tables-legacy-restore
ip6tables-legacy-save
ip6tables-nft
ip6tables-nft-restore
ip6tables-nft-save
ip6tables-restore
ip6tables-restore-translate
ip6tables-save
ip6tables-translate
ipcmk
ipcrm
ipcs
ipmaddr
iptables
iptables-legacy
iptables-legacy-restore
iptables-legacy-save
iptables-nft
iptables-nft-restore
iptables-nft-save
iptables-restore
iptables-restore-translate
iptables-save
iptables-translate
iptables-xml
iptunnel
irqtop
isosize
isympy
jobs
join
journalctl
jp.py
jq
jsondiff
jsonpatch
jsonpointer
jsonschema
kill
killall
kubectl
lambda-builders
last
lastb
lastlog
ldattach
ldconfig
ldd
ld.so
less
lessecho
lesskey
lesspipe.sh
lexgrog
link
linux32
linux64
ln
lnstat
locale
localectl
localedef
logger
login
loginctl
logname
look
losetup
ls
lsblk
lscpu
lsipc
lsirq
lslocks
lslogins
lsmem
lsns
make
make-dummy-cert
man
mandb
man.man-db
manpath
man-recode
mariadb
mariadb-access
mariadb-admin
mariadb-binlog
mariadb-check
mariadb-dump
mariadb-find-rows
mariadb-import
mariadb-plugin
mariadb-show
mariadb-slap
mariadb-waitpid
markdown-it
mcookie
md5sum
mesg
mii-diag
mii-tool
mkdir
mkfifo
mkfs
mkfs.cramfs
mkfs.minix
mkfs.xfs
mkhomedir_helper
mknod
mkswap
mktemp
modulemd-validator
mongosh
more
mount
mountpoint
msql2mysql
mv
mysql
mysqlaccess
mysqladmin
mysqlbinlog
mysqlcheck
mysqldump
mysql_find_rows
mysqlimport
mysql_plugin
mysqlshow
mysqlslap
mysql_waitpid
namei
nameif
nano
neqn
netstat
networkctl
newgidmap
newgrp
newuidmap
newusers
nice
nl
node
node-18
nohup
nologin
normalizer
npm
npm-18
nproc
npx
npx-18
nroff
nsenter
nstat
numfmt
od
oomctl
openssl
p11-kit
pam_console_apply
pam_namespace_helper
pam_timestamp_check
partx
paste
pathchk
pbr
peekfd
perl
perl5.32.1
perldoc
pg_dump
pg_dumpall
pg_isready
pgrep
pg_restore
pg_upgrade
pic
piconv
pidof
pidwait
pigz
ping
ping6
pinky
pip
pip-3
pip3
pip-3.9
pip3.9
pivot_root
pkill
pldd
plipconfig
pmap
pod2man
pod2text
pod2usage
portablectl
post-grohtml
poweroff
pr
preconv
pre-grohtml
printenv
printf
prlimit
prtstat
ps
pslog
psql
pstree
pstree.x11
ptx
pwck
pwconv
pwd
pwdx
pwhistory_helper
pwmake
pwscore
pwsh
pwunconv
__pycache__
pydoc
pydoc3
pydoc3.9
pygmentize
python
python3
python3.9
rdisc
rdma
read
readlink
readprofile
realpath
reboot
reindexdb
rename
renew-dummy-cert
renice
reset
resizepart
resolvconf
resolvectl
rev
rfkill
rm
rmdir
rnano
route
routef
routel
rpm
rpm2archive
rpm2cpio
rpmdb
rpmkeys
rpmquery
rpmverify
rtacct
rtcwake
rtmon
rtpr
rtstat
runc
runcon
runlevel
runuser
rvim
sam
sasldblistusers2
saslpasswd2
scalar
scp
script
scriptlive
scriptreplay
sdiff
sed
seq
session-manager-plugin
setarch
setcap
setfacl
setpriv
setsid
setterm
sfdisk
sftp
sg
sh
sha1sum
sha224sum
sha256sum
sha384sum
sha512sum
shred
shuf
shutdown
skill
slabtop
slattach
sleep
slugify
snice
soelim
soelim.groff
sort
sotruss
split
sprof
ss
ssh
ssh-add
ssh-agent
ssh-copy-id
ssh-keygen
ssh-keyscan
stat
stdbuf
stty
su
sudo
sudoedit
sudoreplay
sulogin
sum
swaplabel
swapoff
swapon
switch_root
sync
sysctl
systemctl
systemd-analyze
systemd-ask-password
systemd-cat
systemd-cgls
systemd-cgtop
systemd-creds
systemd-delta
systemd-detect-virt
systemd-dissect
systemd-escape
systemd-firstboot
systemd-id128
systemd-inhibit
systemd-machine-id-setup
systemd-mount
systemd-notify
systemd-path
systemd-resolve
systemd-run
systemd-socket-activate
systemd-stdio-bridge
systemd-sysext
systemd-sysusers
systemd-tmpfiles
systemd-tty-ask-password-agent
systemd-umount
tabs
tac
tail
tar
taskset
tbl
tc
tee
telinit
test
tic
timedatectl
timeout
tipc
tload
tmux
toe
top
touch
tput
tr
tracepath
tracepath6
troff
true
truncate
trust
tset
tsort
tty
type
tzselect
uclampset
ul
ulimit
umask
umount
unalias
uname
uname26
unexpand
uniq
unix_chkpwd
unix_update
unlink
unpigz
unshare
unxz
unzip
unzipsfx
update-alternatives
update-ca-trust
uptime
useradd
userdbctl
userdel
usermod
users
utmpdump
uuidgen
uuidparse
vacuumdb
vdir
vi
vigr
vim
vimdiff
vimtutor
vipw
visudo
vmstat
w
wait
wall
watch
watchmedo
wc
wdctl
wget
whatis
whatis.man-db
wheel
whereis
which
who
whoami
wipefs
write
x86_64
xargs
xfs_admin
xfs_bmap
xfs_copy
xfs_db
xfs_estimate
xfs_freeze
xfs_fsr
xfs_growfs
xfs_info
xfs_io
xfs_logprint
xfs_mdrestore
xfs_metadump
xfs_mkfile
xfs_ncheck
xfs_quota
xfs_repair
xfs_rtcp
xfs_spaceman
xmlcatalog
xmllint
xmlwf
xtables-legacy-multi
xtables-monitor
xtables-nft-multi
xxd
xz
xzcat
xzcmp
xzdec
xzdiff
xzegrep
xzfgrep
xzgrep
xzless
xzmore
yes
yum
zcat
zcmp
zdiff
zdump
zegrep
zfgrep
zforce
zgrep
zic
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
zless
zmore
znew
zramctl
zsh
zsoelim
色々あるなという感覚です。mariadb
やpsql
もありますね。
IPアドレスは10.20.0.64
でした。
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:b7:22:06:68 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
4: ens6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
link/ether 06:34:ce:8d:b6:25 brd ff:ff:ff:ff:ff:ff
altname enp0s6
altname eni-0fda6b87374bb77e9
altname device-number-1
inet 10.20.0.64/24 scope global ens6
valid_lft forever preferred_lft forever
5: devfile-veth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 56:83:3b:bc:d5:91 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.0.2/32 scope global devfile-veth0
valid_lft forever preferred_lft forever
ディスクは/home
でパーティションは切られていませんでした。
$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 16G 3.5G 12G 24% /
tmpfs tmpfs 64M 0 64M 0% /dev
shm tmpfs 64M 0 64M 0% /dev/shm
/dev/nvme1n1 ext4 16G 3.5G 12G 24% /root
/dev/nvme0n1p1 xfs 30G 13G 18G 44% /aws/mde/mde
EC2インスタンスへの疎通確認
EC2インスタンスへの疎通確認を行います。
$ ping -c 4 10.20.0.198
PING 10.20.0.198 (10.20.0.198) 56(84) bytes of data.
64 bytes from 10.20.0.198: icmp_seq=1 ttl=127 time=1.58 ms
64 bytes from 10.20.0.198: icmp_seq=2 ttl=127 time=0.207 ms
64 bytes from 10.20.0.198: icmp_seq=3 ttl=127 time=0.198 ms
64 bytes from 10.20.0.198: icmp_seq=4 ttl=127 time=0.199 ms
--- 10.20.0.198 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3067ms
rtt min/avg/max/mdev = 0.198/0.545/1.577/0.595 ms
問題なくできました。
Direct ConnectやSite-to-Site VPNを使ってオンプレミスネットワークへ接続しているのであれば、疎通確認にも使えそうです。
外部サイトへのアクセス
CloudShell VPC environmentからhttps://dev.classmethod.jpにアクセスします。
$ curl <https://dev.classmethod.jp> -v -m 5
- Host dev.classmethod.jp:443 was resolved.
- IPv6: 2600:9000:26a7:1e00:18:2b7:4cc0:93a1, 2600:9000:26a7:d600:18:2b7:4cc0:93a1, 2600:9000:26a7:f000:18:2b7:4cc0:93a1, 2600:9000:26a7:7200:18:2b7:4cc0:93a1, 2600:9000:26a7:8200:18:2b7:4cc0:93a1, 2600:9000:26a7:9400:18:2b7:4cc0:93a1, 2600:9000:26a7:9000:18:2b7:4cc0:93a1, 2600:9000:26a7:f400:18:2b7:4cc0:93a1
- IPv4: 18.172.52.84, 18.172.52.93, 18.172.52.11, 18.172.52.102
- Trying 18.172.52.84:443...
- Trying [2600:9000:26a7:1e00:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:1e00:18:2b7:4cc0:93a1: Cannot assign requested address
- Trying [2600:9000:26a7:d600:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:d600:18:2b7:4cc0:93a1: Cannot assign requested address
- Trying [2600:9000:26a7:f000:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:f000:18:2b7:4cc0:93a1: Cannot assign requested address
- Trying [2600:9000:26a7:7200:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:7200:18:2b7:4cc0:93a1: Cannot assign requested address
- Trying [2600:9000:26a7:8200:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:8200:18:2b7:4cc0:93a1: Cannot assign requested address
- Trying [2600:9000:26a7:9400:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:9400:18:2b7:4cc0:93a1: Cannot assign requested address
- Trying [2600:9000:26a7:9000:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:9000:18:2b7:4cc0:93a1: Cannot assign requested address
- Trying [2600:9000:26a7:f400:18:2b7:4cc0:93a1]:443...
- Immediate connect fail for 2600:9000:26a7:f400:18:2b7:4cc0:93a1: Cannot assign requested address
- ipv4 connect timeout after 2500ms, move on!
- Trying 18.172.52.93:443...
- ipv4 connect timeout after 1248ms, move on!
- Trying 18.172.52.11:443...
- ipv4 connect timeout after 624ms, move on!
- Trying 18.172.52.102:443...
- Connection timed out after 5001 milliseconds
- Closing connection
curl: (28) Connection timed out after 5001 milliseconds
タイムアウトになり接続はできませんでした。
これはCloudShellがインターネットへのルーティング経路を持っていないためです。
AWS公式ドキュメントにはパブリックサブネットに配置してもパブリックIPアドレスは割り当てられないと記載がありました。
Public IP addresses are not allocated to CloudShell VPC environments by default. VPC environments created in public subnets with routing tables configured to route all traffic to Internet Gateway will not have access to public internet, but private subnets configured with Network Address Translation (NAT) have access to public internet. VPC environments created in such private subnets will have access to public internet.
CloudShell VPC environmentのENIを確認したところ、確かにパブリックIPアドレスは割り当てられていません。
$ aws ec2 describe-network-interfaces \
--filters Name=network-interface-id,Values="eni-0fda6b87374bb77e9"
{
"NetworkInterfaces": [
{
"Attachment": {
"AttachTime": "2024-06-18T07:31:46+00:00",
"AttachmentId": "eni-attach-044d7e5c351c2c026",
"DeleteOnTermination": false,
"DeviceIndex": 1,
"NetworkCardIndex": 0,
"InstanceOwnerId": "289001025337",
"Status": "attached"
},
"AvailabilityZone": "ap-northeast-1a",
"Description": "Elastic network interface managed by AWS CloudShell service.",
"Groups": [
{
"GroupName": "non-97-test-sg-cloudshell",
"GroupId": "sg-0091d76056a2ef6d0"
}
],
"InterfaceType": "interface",
"Ipv6Addresses": [],
"MacAddress": "06:34:ce:8d:b6:25",
"NetworkInterfaceId": "eni-0fda6b87374bb77e9",
"OwnerId": "<AWSアカウントID>",
"PrivateDnsName": "ip-10-20-0-64.ap-northeast-1.compute.internal",
"PrivateIpAddress": "10.20.0.64",
"PrivateIpAddresses": [
{
"Primary": true,
"PrivateDnsName": "ip-10-20-0-64.ap-northeast-1.compute.internal",
"PrivateIpAddress": "10.20.0.64"
}
],
"RequesterId": "304732609880",
"RequesterManaged": false,
"SourceDestCheck": true,
"Status": "in-use",
"SubnetId": "subnet-0d4be822a6d6571c2",
"TagSet": [
{
"Key": "ManagedByCloudShell",
"Value": ""
}
],
"VpcId": "vpc-081ab1b7c99573078"
}
]
}
ちなみに確認のために叩いたaws ec2 describe-network-interfaces
ですが、CloudShell VPC environmentから実行しても応答がありませんでした。
AWSのサービスエンドポイントへアクセスしたい場合は以下のいずれかの対応が必要になると考えます。
- インターネットへの経路の追加
- VPCエンドポイントの作成
ちなみに、名前解決はどのようにしているのかなと確認したところ、Route 53 ResolverのIPアドレスを参照していました。
$ cat /etc/resolv.conf
search ap-northeast-1.compute.internal
nameserver 10.20.0.2
Webサーバー on EC2へのアクセス
次に、Apache HTTP ServerをEC2インスタンスにインストールし、稼働しているWebサーバー上のコンテンツにCloudShell VPC environmentからアクセスできるか確認します。
httpdのインストールおよび、起動を行います。
sh-5.2$ sudo dnf install httpd -y
Last metadata expiration check: 0:17:00 ago on Tue Jun 18 07:30:10 2024.
Dependencies resolved
===============================================================================================
Package Architecture Version Repository Size
===============================================================================================
Installing:
httpd aarch64 2.4.59-2.amzn2023 amazonlinux 47 k
Installing dependencies:
apr aarch64 1.7.2-2.amzn2023.0.2 amazonlinux 125 k
apr-util aarch64 1.6.3-1.amzn2023.0.1 amazonlinux 100 k
generic-logos-httpd noarch 18.0.0-12.amzn2023.0.3 amazonlinux 19 k
httpd-core aarch64 2.4.59-2.amzn2023 amazonlinux 1.4 M
httpd-filesystem noarch 2.4.59-2.amzn2023 amazonlinux 14 k
httpd-tools aarch64 2.4.59-2.amzn2023 amazonlinux 81 k
libbrotli aarch64 1.0.9-4.amzn2023.0.2 amazonlinux 316 k
mailcap noarch 2.1.49-3.amzn2023.0.3 amazonlinux 33 k
Installing weak dependencies:
apr-util-openssl aarch64 1.6.3-1.amzn2023.0.1 amazonlinux 17 k
mod_http2 aarch64 2.0.27-1.amzn2023.0.2 amazonlinux 161 k
mod_lua aarch64 2.4.59-2.amzn2023 amazonlinux 59 k
Transaction Summary
===============================================================================================
Install 12 Packages
Total download size: 2.3 M
Installed size: 27 M
Downloading Packages:
(1/12): apr-util-openssl-1.6.3-1.amzn2023.0.1.aarch64.rpm 236 kB/s | 17 kB 00:00
.
.
(中略)
.
.
Installed:
apr-1.7.2-2.amzn2023.0.2.aarch64
apr-util-1.6.3-1.amzn2023.0.1.aarch64
apr-util-openssl-1.6.3-1.amzn2023.0.1.aarch64
generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch
httpd-2.4.59-2.amzn2023.aarch64
httpd-core-2.4.59-2.amzn2023.aarch64
httpd-filesystem-2.4.59-2.amzn2023.noarch
httpd-tools-2.4.59-2.amzn2023.aarch64
libbrotli-1.0.9-4.amzn2023.0.2.aarch64
mailcap-2.1.49-3.amzn2023.0.3.noarch
mod_http2-2.0.27-1.amzn2023.0.2.aarch64
mod_lua-2.4.59-2.amzn2023.aarch64
Complete!
$ sudo systemctl enable httpd --now
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
Webサーバー起動完了後、CloudShell VPC environmentからアクセスします。
$ curl <http://10.20.0.198> -I
HTTP/1.1 403 Forbidden
Date: Tue, 18 Jun 2024 07:48:36 GMT
Server: Apache/2.4.59 (Amazon Linux)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html; charset=UTF-8
$ curl <http://10.20.0.198> -v
- Trying 10.20.0.198:80...
- Connected to 10.20.0.198 (10.20.0.198) port 80
> GET / HTTP/1.1
> Host: 10.20.0.198
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Date: Tue, 18 Jun 2024 07:48:38 GMT
< Server: Apache/2.4.59 (Amazon Linux)
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html; charset=UTF-8
<
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host 10.20.0.198 left intact
問題なくアクセスできました。やったぜ。
dnfリポジトリへのアクセス
ふと、インターネットに接続されていない状態でdnf上のパッケージを参照できるのか気になったので試してみます。
$ dnf repolist
repo id repo name
amazonlinux Amazon Linux 2023 repository
$ dnf search postgresql
^CAmazon Linux 2023 repository [ === ] --- B/s | 0 B --:-- ETAmazon Linux 2023 repository 0.0 B/s | 0 B 00:03
Error: Failed to download metadata for repo 'amazonlinux': Cannot prepare internal mirrorlist: Interrupted by signal
Ignoring repositories: amazonlinux
============================================================ Name & Summary Matched: postgresql ============================================================
postgresql15.x86_64 : PostgreSQL client programs
postgresql15-private-libs.x86_64 : The shared libraries required only for this build of PostgreSQL server
いつまで待ってもdnf search
は完了しませんでした。S3のゲートウェイ型VPCエンドポイントは存在するため「できそうだな」と思ったのですができません。
そのため、インターネットへの経路がない状態でdnfを使ってパッケージをインストールすることはできないようです。
なお、psqlはデフォルトでインストールされているからかdnf search postgresql
を実行中にキャンセルしたところ、インストール済みと思われるパッケージが表示されました。
パブリックIPの自動割り当ての有効化
CloudShell VPC environmentにパブリックIPアドレスを割り当てます。
まず、CloudShell VPC environmentのENIにて、パブリックIPの自動割り当てを有効化することによってパブリックIPアドレスが割り当てられるか確認します。
以下記事のとおり、EC2インスタンスについては動的に追加できるようになりましたが、CloudShell VPC environmentの場合はどうでしょうか。
マネジメントコンソールからCloudShell VPC environmentのENIを選択して、パブリックIPの自動割り当て
を有効にして保存
をクリックします。このネットワークインターフェイスに追加のパブリック IPv4 アドレスを割り当てるには、Elastic IP アドレスを割り当てて、このネットワークインターフェイスに関連付ける必要があります。
と表示されているのが全てな気がしますが、続行します。
内容を確認して確認
をクリックします。
設定して数十分ほど待ちましたが、パブリックIPアドレスは割り当てられませんでした。
ということで、パブリックIPの自動割り当ての有効化ではCloudShell VPC environmentのENIにパブリックIPアドレスを割り当てることは出来ません。
Elastic IPアドレスの関連付け
CloudShell VPC environmentのENIにElastic IPアドレスの関連付けを行った場合はどうでしょうか。
Elastic IPアドレスを発行し、CloudShell VPC environmentのENIのIPアドレスに関連付けます。
パブリックIPアドレスが設定されました。
AWS CLIからでも以下のように確認できます。
$ aws ec2 describe-network-interfaces \
--filters Name=network-interface-id,Values="eni-0fda6b87374bb77e9"
{
"NetworkInterfaces": [
{
"Association": {
"AllocationId": "eipalloc-0674ef97db6fed141",
"AssociationId": "eipassoc-016ddaececd5eaaac",
"IpOwnerId": "<AWSアカウントID>",
"PublicDnsName": "ec2-35-76-83-96.ap-northeast-1.compute.amazonaws.com",
"PublicIp": "35.76.83.96"
},
"Attachment": {
"AttachTime": "2024-06-18T07:31:46+00:00",
"AttachmentId": "eni-attach-044d7e5c351c2c026",
"DeleteOnTermination": false,
"DeviceIndex": 1,
"NetworkCardIndex": 0,
"InstanceOwnerId": "289001025337",
"Status": "attached"
},
"AvailabilityZone": "ap-northeast-1a",
"Description": "Elastic network interface managed by AWS CloudShell service.",
"Groups": [
{
"GroupName": "non-97-test-sg-cloudshell",
"GroupId": "sg-0091d76056a2ef6d0"
}
],
"InterfaceType": "interface",
"Ipv6Addresses": [],
"MacAddress": "06:34:ce:8d:b6:25",
"NetworkInterfaceId": "eni-0fda6b87374bb77e9",
"OwnerId": "<AWSアカウントID>",
"PrivateDnsName": "ip-10-20-0-64.ap-northeast-1.compute.internal",
"PrivateIpAddress": "10.20.0.64",
"PrivateIpAddresses": [
{
"Association": {
"AllocationId": "eipalloc-0674ef97db6fed141",
"AssociationId": "eipassoc-016ddaececd5eaaac",
"IpOwnerId": "<AWSアカウントID>",
"PublicDnsName": "ec2-35-76-83-96.ap-northeast-1.compute.amazonaws.com",
"PublicIp": "35.76.83.96"
},
"Primary": true,
"PrivateDnsName": "ip-10-20-0-64.ap-northeast-1.compute.internal",
"PrivateIpAddress": "10.20.0.64"
}
],
"RequesterId": "304732609880",
"RequesterManaged": false,
"SourceDestCheck": true,
"Status": "in-use",
"SubnetId": "subnet-0d4be822a6d6571c2",
"TagSet": [
{
"Key": "ManagedByCloudShell",
"Value": ""
}
],
"VpcId": "vpc-081ab1b7c99573078"
}
]
}
なお、EIP割り当て前にCloudShell VPC environmentからaws ec2 describe-network-interfaces
を実行しても応答はありませんでしたが、EIP割り当て後は先述のレスポンスが返ってきました。
外部サイトへのアクセス (Elastic IPアドレス割り当て後)
再度、CloudShell VPC environmentからhttps://dev.classmethod.jpにアクセスします。
$ curl <https://dev.classmethod.jp> -I -m 5
HTTP/2 200
content-type: text/html; charset=utf-8
accept-ranges: none
cache-control: max-age=45, stale-if-error=21600
date: Tue, 18 Jun 2024 07:59:50 GMT
server: envoy
x-envoy-upstream-service-time: 149
vary: Accept-Encoding
x-cache: Miss from cloudfront
via: 1.1 8f04fc9fa6b5d8f6fb1d186398be5c6a.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-P2
alt-svc: h3=":443"; ma=86400
x-amz-cf-id: 5TZC2OQAw1aYNzW0fW6CmJT_OqCWdim_gSgidsVrgXiTCVknJZbcuw==
server-timing: cdn-upstream-layer;desc="REC",cdn-upstream-dns;dur=0,cdn-upstream-connect;dur=8,cdn-upstream-fbl;dur=160,cdn-cache-miss,cdn-pop;desc="NRT20-P2",cdn-rid;desc="5TZC2OQAw1aYNzW0fW6CmJT_OqCWdim_gSgidsVrgXiTCVknJZbcuw==",cdn-downstream-fbl;dur=171
インターネット上のリソースにも疎通できるようになっていました。
インターネット上のリソースへのpingも問題なく叩けられます。
$ ping 1.1.1.1 -c 4
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=54 time=2.23 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=54 time=2.28 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=54 time=2.20 ms
64 bytes from 1.1.1.1: icmp_seq=4 ttl=54 time=2.27 ms
--- 1.1.1.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 2.200/2.245/2.278/0.030 ms
RDS DBインスタンスへの接続
RDS DBインスタンスへの接続を行います。
その前にせっかくなので、dnf search postgresql
を叩いてdnfで設定しているリポジトリにアクセスできるか確認します。
$ dnf search postgresql
Amazon Linux 2023 repository 47 MB/s | 25 MB 00:00
Last metadata expiration check: 0:00:08 ago on Tue 18 Jun 2024 08:00:51 AM UTC.
============================================================ Name & Summary Matched: postgresql ============================================================
collectd-postgresql.x86_64 : PostgreSQL plugin for collectd
postgresql-odbc.x86_64 : PostgreSQL ODBC driver
postgresql15.x86_64 : PostgreSQL client programs
postgresql15-contrib.x86_64 : Extension modules distributed with PostgreSQL
postgresql15-docs.x86_64 : Extra documentation for PostgreSQL
postgresql15-llvmjit.x86_64 : Just-in-time compilation support for PostgreSQL
postgresql15-plperl.x86_64 : The Perl procedural language for PostgreSQL
postgresql15-plpython3.x86_64 : The Python3 procedural language for PostgreSQL
postgresql15-pltcl.x86_64 : The Tcl procedural language for PostgreSQL
postgresql15-private-devel.x86_64 : PostgreSQL development header files for this build of PostgreSQL server
postgresql15-private-libs.x86_64 : The shared libraries required only for this build of PostgreSQL server
postgresql15-server.x86_64 : The programs needed to create and run a PostgreSQL server
postgresql15-server-devel.x86_64 : PostgreSQL development header files and libraries
postgresql15-static.x86_64 : Statically linked PostgreSQL libraries
postgresql15-test.x86_64 : The test suite distributed with PostgreSQL
postgresql15-test-rpm-macros.noarch : Convenience RPM macros for build-time testing against PostgreSQL server
postgresql15-upgrade.x86_64 : Support for upgrading from the previous major release of PostgreSQL
================================================================= Name Matched: postgresql =================================================================
postgresql-odbc-tests.x86_64 : Testsuite files for psqlodbc
postgresql15-upgrade-devel.x86_64 : Support for build of extensions required for upgrade process
=============================================================== Summary Matched: postgresql ================================================================
BabelfishDump.x86_64 : Postgresql dump utilities modified for Babelfish
apr-util-pgsql.x86_64 : APR utility library PostgreSQL DBD driver
libpgtypes.x86_64 : Map PostgreSQL database types to C equivalents
libpq.x86_64 : PostgreSQL client library
libpq-devel.x86_64 : Development files for building PostgreSQL client tools
perl-DBD-Pg.x86_64 : A PostgreSQL interface for Perl
perl-DateTime-Format-Pg.noarch : Parse and format PostgreSQL dates and times
php8.1-pgsql.x86_64 : A PostgreSQL database module for PHP 8.1
php8.2-pgsql.x86_64 : A PostgreSQL database module for PHP 8.2
postfix-pgsql.x86_64 : Postfix PostgreSQL map support
python-psycopg2-doc.x86_64 : Documentation for psycopg python PostgreSQL database adapter
python3-psycopg2.x86_64 : A PostgreSQL database adapter for Python 3
python3-psycopg2-debug.x86_64 : A PostgreSQL database adapter for Python 3 (debug build)
python3-psycopg2-tests.x86_64 : A testsuite for A PostgreSQL database adapter for Python 2
問題なくアクセスできるようになりました。
Secrets Managerから認証情報を取得して、psql
でRDS DBインスタンスに接続します。
$ get_secrets_value=$(aws secretsmanager get-secret-value \
--secret-id 'rds!db-4a5c067d-186c-43df-9ee6-126092ecac72' \
--region ap-northeast-1 \
| jq -r .SecretString)
$ export PGHOST=non-97-test-rds.cukqrmgu6hz5.ap-northeast-1.rds.amazonaws.com
$ export PGPORT=5432
$ export PGDATABASE=postgres
$ export PGUSER=$(echo "${get_secrets_value}" | jq -r .username)
$ export PGPASSWORD=$(echo "${get_secrets_value}" | jq -r .password)
$ psql
psql (15.7, server 16.3)
WARNING: psql major version 15, server major version 16.
Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
postgres=>
postgres=> \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-----------+----------+----------+-------------+-------------+------------+-----------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
rdsadmin | rdsadmin | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | rdsadmin=CTc/rdsadmin
template0 | rdsadmin | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/rdsadmin +
| | | | | | | rdsadmin=CTc/rdsadmin
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres +
| | | | | | | postgres=CTc/postgres
(4 rows)
接続できました。やったぜ。
気になる操作感ですが、特に遅延は感じませんでした。問題なくコマンドを叩けました。
postgres=> SELECT *from pg_stat_activity;
datid | datname | pid | leader_pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | xact_start | query_start | state_change | wait_event_type | wait_event | state | backend_xid | backend_xmin | query_id | query | backend_type
-------+----------+------+------------+----------+----------+------------------------+-------------+-----------------+-------------+-------------------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+---------------------+--------+-------------+--------------+----------------------+----------------------------------+------------------------------
| | 713 | | 10 | rdsadmin | | | | | 2024-06-18 07:29:35.143053+00 | | | | Activity | LogicalLauncherMain | | | | | | logical replication launcher
| | 712 | | | | | | | | 2024-06-18 07:29:35.143076+00 | | | | Activity | AutoVacuumMain | | | | | | autovacuum launcher
16384 | rdsadmin | 863 | | 10 | rdsadmin | PostgreSQL JDBC Driver | | | -1 | 2024-06-18 07:30:38.955577+00 | | 2024-06-18 08:08:33.745464+00 | 2024-06-18 08:08:33.745483+00 | Client | ClientRead | idle | | | | SELECT value FROM rds_heartbeat2 | client backend
16384 | rdsadmin | 845 | | 10 | rdsadmin | | | | -1 | 2024-06-18 07:30:22.399109+00 | | 2024-06-18 08:08:39.674037+00 | 2024-06-18 08:08:39.674115+00 | Client | ClientRead | idle | | | 2064869707185898531 | COMMIT | client backend
5 | postgres | 2364 | | 16408 | postgres | psql | 10.20.0.64 | | 35948 | 2024-06-18 08:05:24.530378+00 | 2024-06-18 08:08:40.282634+00 | 2024-06-18 08:08:40.282634+00 | 2024-06-18 08:08:40.282637+00 | | | active | | 900 | -6114308060117779060 | SELECT* from pg_stat_activity; | client backend
| | 709 | | | | | | | | 2024-06-18 07:29:35.125546+00 | | | | Activity | BgWriterHibernate | | | | | | background writer
| | 708 | | | | | | | | 2024-06-18 07:29:35.124979+00 | | | | Activity | CheckpointerMain | | | | | | checkpointer
| | 711 | | | | | | | | 2024-06-18 07:29:35.142572+00 | | | | Activity | WalWriterMain | | | | | | walwriter
(8 rows)
postgres=> SELECT inet_client_addr();
inet_client_addr
------------------
10.20.0.64
(1 row)
postgres=> SELECT * FROM pg_user WHERE usename = CURRENT_USER;
usename | usesysid | usecreatedb | usesuper | userepl | usebypassrls | passwd | valuntil | useconfig
----------+----------+-------------+----------+---------+--------------+----------+----------+-----------
postgres | 16408 | t | f | f | f | ******** | infinity |
(1 row)
簡単にCLIで操作したい場合は非常に役立ちそうです。
CloudShell VPC environmentを再起動した場合
CloudShell VPC environmentを再起動した場合を確認します。
AWS公式ドキュメントには永続ストレージはサポートされていないと記載がありました。
VPC environments do not support persistent storage. Storage is ephemeral. Data and home directory are deleted when an active environment session ends.
ホームディレクトリに適当にファイルを作成します。
$ pwd
/home/cloudshell-user
$ echo test.txt > test.txt
$ ls -l
total 4
-rw-r--r--. 1 cloudshell-user cloudshell-user 9 Jun 18 09:36 test.txt
CloudShell VPC environmentを再起動します。Restarting non-97-test-cloudshell environment will immediately stop all the active CloudShell sessions of this environment in the current AWS Region. It will also delete all the data in the environment's home directory.
とホームディレクトリ上のデータが削除されると警告されました。
再起動後のCloudShell VPC environmentを確認すると、確かにホームディレクトリ上のファイルが削除されていました。
$ pwd
/home/cloudshell-user
$ ls -l
total 0
また、関連づくENIおよびプライベートIPアドレスは変わっており、EIPの関連付けも解除されていました。
$ aws ec2 describe-network-interfaces \
--filters Name=network-interface-id,Values="eni-049d976a473ae0512"
{
"NetworkInterfaces": [
{
"Attachment": {
"AttachTime": "2024-06-18T09:36:59+00:00",
"AttachmentId": "eni-attach-0bab207fc088f2982",
"DeleteOnTermination": false,
"DeviceIndex": 1,
"NetworkCardIndex": 0,
"InstanceOwnerId": "289001025337",
"Status": "attached"
},
"AvailabilityZone": "ap-northeast-1a",
"Description": "Elastic network interface managed by AWS CloudShell service.",
"Groups": [
{
"GroupName": "non-97-test-sg-cloudshell",
"GroupId": "sg-0091d76056a2ef6d0"
}
],
"InterfaceType": "interface",
"Ipv6Addresses": [],
"MacAddress": "06:16:e3:28:60:f7",
"NetworkInterfaceId": "eni-049d976a473ae0512",
"OwnerId": "<AWSアカウントID>",
"PrivateDnsName": "ip-10-20-0-175.ap-northeast-1.compute.internal",
"PrivateIpAddress": "10.20.0.175",
"PrivateIpAddresses": [
{
"Primary": true,
"PrivateDnsName": "ip-10-20-0-175.ap-northeast-1.compute.internal",
"PrivateIpAddress": "10.20.0.175"
}
],
"RequesterId": "304732609880",
"RequesterManaged": false,
"SourceDestCheck": true,
"Status": "in-use",
"SubnetId": "subnet-0d4be822a6d6571c2",
"TagSet": [
{
"Key": "ManagedByCloudShell",
"Value": ""
}
],
"VpcId": "vpc-081ab1b7c99573078"
}
]
}
サクッとVPC内やオンプレミスネットワーク上のリソースにアクセスしたい場合に
CloudShell VPC environment から VPC内のEC2インスタンスやRDS DBインスタンスに接続してみました。
サクッとVPC内やオンプレミスネットワーク上のリソースにアクセスしたい場合には便利そうですね。
特にAWSのAPIを叩いたり、インターネット上に抜ける通信を行う必要がない場合は、VPCエンドポイントやNAT Gatewayへの経路を用意する必要がないのは大きいです。非常にお手軽です。仮に必要になったとしてもEIPを関連付けるだけなので、コストも非常に安価だと感じています。
一方で、CloudShell VPC environmentではファイルのアップロードやダウンロードはできません。
また、永続ストレージもサポートされていないため、一時的な作業用途で使うのが良いかと考えます。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!