ユニークなS3バケット名かを判定してS3バケットが作れるシェルスクリプトを作ってみた

「世界に一つだけのS3バケット」を作りたい……できればコンソールに張り付く事なく! シェルスクリプトを駆使してユニークなS3バケット名かを判定した上でS3バケットを作成できるようにしてみました。
2019.11.23

急に寒さが増しましたが、皆さまはいかがお過ごしでしょうか。

▲ 「正しい羽毛布団と毛布の重ね方のイラスト 」ですって

丁寧に布団の層を作り上げても一晩で台無しになっています。寒くなったら少しはマシになると思っていました。 こんにちは、AWS事業本部のShirotaです。寝相の悪さが露呈した今、渡航時が心配で堪りません。去年は暴れたのかな

早速ですが、寒さに負けずに本題に入っていきましょう。

量産型バケットを作ろうとして怒られた話

先日、Amazon Comprehendを触った時にS3バケットを用意しようとしたところ、以下のようなエラーが出てしまいました。

▲ 皆同じ事を考えるものだ

これは「既に同じ名前のS3バケットがある」時にバケットが作成できずに出るエラーです。 S3のバケット名は、 リージョン関係なくユニークな名前でないといけません 。 S3のバケット名がユニークであるかどうかを調べる方法は、AWS公式に以下のように記載があります。

Amazon S3 コンソールを使用して、既存のバケットを確認できます。または、head-bucket AWS CLI コマンドを実行して、既にその名前を付けたバケットがあることを確認できます。

引用元: Amazon S3 からの「バケット名が既に存在します」または「BucketAlreadyExists」エラーを解決するには、どうすれば良いですか?

前者の「コンソールを使用して、既存のバケットを確認」は前述した状況ですね。 後者の「head-bucket AWS CLIコマンドを実行」に関しては、実行すると以下のようになります。

# バケットが存在かつアクセスする権利がある場合  
$ aws s3api head-bucket --bucket バケット名  
$  
  
# バケットが存在するがアクセスする権利がない場合  
$ aws s3api head-bucket --bucket バケット名  
An error occurred (403) when calling the HeadBucket operation: Forbidden  
  
# バケットが存在しない場合  
$ aws s3api head-bucket --bucket バケット名  
An error occurred (404) when calling the HeadBucket operation: Not Found

バケットが存在しない場合について、一つ補足したい事があります。 それは、「バケットが存在しない」=「そのバケット名でバケットが作成できる」ではない という事です。 一旦、ここでバケットの命名規則について説明致します。

S3バケットの命名規則について

バケットの命名については規則が存在します。 リージョン関係なくユニークな名前でないといけない、とお話し致しましたがそれ以外にも色々な規則が存在します。 例えば、以下のような命名規則が存在します。

  • バケット名の文字数は3~63文字以内
  • 大文字、アンダースコアをバケット名に含める事はできない
  • ピリオドは連続してはいけない

命名規則の詳細は、以下のAWS公式ガイドをご参照下さい。

バケットの制約と制限

色々な命名規則がありますが、基本的には「DNSで使用できる命名を意識する」事で規則に沿った命名をする事ができます。 コンソールでバケットを作成する際にはバケット名を入力するとリアルタイムで命名規則に沿っているかを判定してくれる為、命名規則を正確に覚えていなくても命名規則に沿ったバケット名を考える事が簡単です。

▲ たった10文字でもここまで規則を破れた

この場合は、

  • バケット名にピリオドが連続する箇所がある
  • バケット名に英語の大文字が含まれている
  • バケット名の末尾が半角小文字の英数字でない

3つの命名規則違反をしている事が分かります。

ここで、上記の命名規則違反のバケット名でhead-bucket AWS CLIコマンドを実行してみます。

$ aws s3api head-bucket --bucket teki..Tou-  
  
An error occurred (404) when calling the HeadBucket operation: Not Found

バケットが存在しない場合と同じエラーが出ました 。 ちなみに、命名規則違反でも文字数が足りない場合には、以下のエラーが発生しました。

$ aws s3api head-bucket --bucket t  
  
An error occurred (400) when calling the HeadBucket operation: Bad Request

これらの事象より、head-bucket AWS CLIコマンドを用いて調べたエラーメッセージだけを見て「このバケット名は命名規則に従っていて、まだ誰も利用していない名前なので作成できる」と 完全に言い切る事は不可能なのです

……かと言って、毎回コンソールに名前を打ち込み命名規則に従っていてユニークなバケット名であるかを調べる事は面倒に感じる方もいると思います。私も思いました。

AWS CLIで調べてAWS CLIでバケット作成までコンソールに触れず完結させたい…… 」と。

CLI上で完結できるようにした

と言う訳で、コンソールを使用する事なく完結できるようにしてみました。 今回は、シェルスクリプト(bash)を利用しています。 やった事は、

  • バケット名の命名規則をチェックする
  • その上で、バケット名が重複していないかを調べる
  • 作成できるバケット名だと分かった場合、バケット作成まで実行できるようにする

の三点です。 命名規則に関しては正規表現で確認し、確認できたバケット名のみをAWS CLIで重複確認するようにしました。 後は、実際にスクリプトを見て頂いた方が分かりやすいと思うのでスクリプトを以下に掲載します。

作成したシェルスクリプト

実際に使用する際は、AWS CLIのセットアップ等の事前準備を完了させてからご利用下さい。

#!/bin/bash  
  
DNS=`echo $1 | grep -cwE '^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$'` # S3バケット名の使用可能文字および文字数を守っているか  
  
if [ ${DNS} -eq 0 ];then  
    echo "半角小文字英数字とハイフン以外の文字を使っている、バケット名の先頭または末尾が小文字の英数字でない、または3文字以上63文字以下になってない可能性があります"  
    exit  
fi  
  
IPADDR=`echo $1 | grep -cwE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'` # S3バケット名がIPアドレス形式(XXX.XXX.XXX.XXX)でないか  
  
if [ $IPADDR -eq 1 ];then  
    echo "S3バケット名にIPアドレス形式は使用できません"  
    exit  
fi  
  
CONTSYMBOL=`echo $1 | grep -cE '\.{2,}'` # S3バケット名にピリオドが連続していないか  
  
if [ $CONTSYMBOL -eq 1 ];then  
    echo "ピリオドが連続しています"  
    exit  
fi  
  
UNIQUE=`aws s3api head-bucket --bucket $1 2>&1 | grep -cE '404'` # 命名規則に則った上での404エラーはバケットが存在しなくて作成可能だとみなす
  
if [ $UNIQUE -eq 0 ];then  
    echo "重複するS3バケット名が存在しています"  
    exit  
fi  
  
PERIOD=`echo $1 | grep -cE '\.'` # ピリオドが含まれている場合に警告する  
  
if [ $PERIOD -eq 1 ];then  
    echo "$1はユニークなS3バケット名ですがピリオドが含まれているとSSLワイルドカード証明書が使えなくなる為、ピリオド抜きに変更をお勧めします"  
    exit  
fi  
# 以下、ユニークなS3バケット名でバケットを作成するか選べる  
echo "$1はユニークなS3バケット名です。バケットを作成する場合はyesと入力して下さい:"  
read -p "Make S3 Bucket?:" S3MAKE  
  
if [ "$S3MAKE" = yes ];then  
    aws s3 mb s3://$1  
else  
    exit  
fi

実際に使ってみる

実際に使ってみると、以下のような動作をします。

# 何らかのバケット名の命名規則に違反する場合
$ ./s3-unique-name.sh -test-unique  
半角小文字英数字とハイフン以外の文字を使っている、バケット名の先頭または末尾が小文字の英数字でない、または3文字以上63文字以下になってない可能性があります  
  
# バケット名がIPアドレス形式だった場合  
$ ./s3-unique-name.sh 192.168.12.34  
S3バケット名にIPアドレス形式は使用できません  
  
# ピリオドが連続している場合
$ ./s3-unique-name.sh test..s3-unique  
ピリオドが連続しています  
  
# 重複したバケット名が存在する場合  
$ ./s3-unique-name.sh test-aws-comprehend  
重複するS3バケット名が存在しています  
  
# IPアドレス形式以外でバケット名にピリオドが含まれている場合  
$ ./s3-unique-name.sh test.aws.comprehend  
test.aws.comprehendはユニークなS3バケット名ですがピリオドが含まれているとSSLワイルドカード証明書が使えなくなる為、ピリオド抜きに変更をお勧めします  
  
# 命名規則に従ったユニークなバケット名だった場合
$ ./s3-unique-name.sh test-comprehend-201911-2  
test-comprehend-201911-2はユニークなS3バケット名です。バケットを作成する場合はyesと入力して下さい:  
Make S3 Bucket?:yes  
make_bucket: test-comprehend-201911-2

S3バケット名を考える際に考慮しておくと嬉しい事

今回は、S3バケットの作成が最低限できるような命名を作成するのに使えるシェルスクリプトを作成しました。 実際、S3バケットの命名をする際には命名規則に従いユニークなバケット名を考える事は必須ですが、他にも以下の点を意識してバケット名を考えると後々嬉しい事が増えるかもしれません。

命名ルールを定義しておく

命名ルールを定義しておくと後々命名する際に楽になれるかと思われます。 例えば、公開予定の無いS3バケットだったらアカウントIDを入れた命名ルールを定義しておくとユニークなバケット名をつける時に重複の可能性が減らせます。 命名ルールについての考え方は、弊社 城岸のブログが分かりやすく説明しているので参考にどうぞ。

弊社で使っているAWSリソースの命名規則を紹介します

ピリオドを含まないバケット名を考える

今回のシェルスクリプトにも入れていましたが、ピリオドを含むバケット名はS3を仮想ホスト名(http://.s3.amazonaws.com) で利用する可能性がある場合SSLワイルドカード証明書が使えなくなってしまう為、仮想ホスト名でバケットにアクセスする可能性がある場合は「ピリオドを含まないバケット名」を考えておいた方がより良いです。 いざHTTPSでバケットにアクセスしたいと思った時にハマらなくなるかと思われます。

このブログがユニークなS3バケット名の選定に、少しでもお役に立てれば幸いです。