ちょっと話題の記事

クレデンシャルの適切な扱い方 ー AWS SDK for Goの場合

2017.06.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。

AWS CLIやAWS SDKを利用すれば、AWSでリソースを自由に操作できます。 この時、認証情報(クレデンシャル)が必要ですが、適切に扱わなければなりません。 特にアクセスキーの扱いは慎重に行い、可能な限りアクセスキーを利用しないことが大切です。

AWS SDK fo Goでのクレデンシャルの扱いについてまとめました。

AWS SDK for Goを使う流れ

はじめにAWS SDK for Goでのサービス利用手順について確認します。 例えば、EC2サービスを利用するには次のようなコードです。

sess := session.Must(session.NewSession())
svc := ec2.New(
    sess,
    aws.NewConfig().WithRegion("ap-northeast-1"),
)
fmt.Println(svc.DescribeInstances(nil))

Sessionサービス (ec2)の作成がポイントです。

Sessionの作成

幾つかのオプションがありますが、ほとんどの場合、Sessionを作成するには、Must関数を利用します。

sess := session.Must(session.NewSession())

Session作成時、デフォルトリージョンも設定できます。 自分はサービス作成時に指定する方が統一化されて良いと考えます。

なお、NewSession関数は戻り値としてsessionとerrorを返します。 エラーハンドリングが必要となるため、次のように冗長なコードが生まれるでしょう。

// Mustを使わないとこう書かなければならない
sess, err := session.NewSession()
if err != nil {
    panic(err)
}

sessionとerrorを引数に持つMust関数を利用すれば、このエラーハンドリングはMust関数内で行われ、コードがスッキリします。

サービスの作成

サービス(クライアント)の作成は、各サービスのNew関数を利用します。 ひとつ目の引数にsessionを、ふたつ目の引数にConfigを指定しています。

sess := session.Must(session.NewSession())
svc := ec2.New(
    sess,
    aws.NewConfig().WithRegion("ap-northeast-1"),
)
fmt.Println(svc.DescribeInstances(nil))

Configは幾つかの作成方法があります。 NewConfig関数WithRegion関数などでメソッドチェーンを利用するのが便利です。

Credentials

はじめに紹介したコードでは、クレデンシャルの取得方法の指定はありません。 デフォルトでは、「いい感じに」クレデンシャル情報が利用されるよう、ConfigのCredentialsに設定されています。

デフォルトのCredentialsでは、環境変数のアクセスキーを参照します。 環境変数にアクセスキーがない場合、クレデンシャルファイルを参照します。 クレデンシャルファイルも参照できない場合に、IAM Roleを利用します。

これらは、CredentialsにChainProviderとして定義されています。

環境変数のアクセスキーを利用する

デフォルトで設定されているCredentialsでは、環境変数を参照します。

アクセスキー(AWS_ACCESS_KEY_IDまたはAWS_ACCESS_KEY)とシークレットキー(AWS_SECRET_ACCESS_KEYまたはAWS_SECRET_KEY)が設定されている場合、これらをクレデンシャルとして利用します。 プログラムの実行時に一時的にアクセスキーとシークレットキーを環境変数に設定して実行する用途で便利です。

クレデンシャルファイルを利用する

ローカルPCなどからAWS CLIやAWS SDKを利用する場合、クレデンシャルファイル(~/.aws/credentinal)にアクセスキーはを記述することが推奨されています。 クレデンシャルファイルを使うことで、プロファイル名を利用すればいいため、アクセスキーを直接参照することがありません。

AWS SDK for Goでデフォルトのクレデンシャルを利用している場合、環境変数AWS_PROFILEからプロファイル名を取得します。 AWS_PROFILEが存在しない場合は「default」です。

明示的にAWS SDK for Goでプロファイル名を指定する場合、sessionを作成する時にNewSessionWithOptions関数を利用します。

profile_name := "profile_name"
sess := session.Must(session.NewSessionWithOptions(session.Options{Profile:profile_name}))
svc := ec2.New(
    sess,
    aws.NewConfig().WithRegion("ap-northeast-1").WithCredentials(),
)
fmt.Println(svc.DescribeInstances(nil))

IAM Roleを利用する

アクセスキーの発行は最終手段です。 EC2インスタンスやLambdaなどでコードを実行する場合、アクセスキーを発行する必要はありません。 必ずIAM Roleを使いましょう。

IAM Roleを利用しているならば、デフォルトのCredentialsで問題ありません。 自動的にIAM RoleからCredentialが取得されます。

アクセスキーを利用する

アクセスキーを利用しなければならない場合は、NewStaticCredentials関数を利用し、ConfigでCredentialsに設定します。

sess := session.Must(session.NewSession())
creds := credentials.NewStaticCredentials(aws_access_key_id, aws_secret_access_key, "")
svc := ec2.New(
    sess,
    aws.NewConfig().WithRegion("ap-northeast-1").WithCredentials(creds),
)
fmt.Println(svc.DescribeInstances(nil))

ただし、アクセスキーの管理場所やローテーションについて充分に注意してください。

Assume Roleを利用する

最後に別のアカウントから権限を委譲されるケース、すなわちAssume Roleを利用するケースを紹介します。 Assume Roleを利用する場合は、stscredsのNewCredentialsWithClientを利用します。 NewCredentials関数の引数にstsクライアントとrole arnを指定してください。

sess := session.Must(session.NewSession())
assumeRoler := sts.New(sess)

creds := stscreds.NewCredentialsWithClient(assumeRoler, "arn:aws:iam::XXXXXXXXXXXX:role/role_name")
svc := ec2.New(
    sess,
    aws.NewConfig().WithRegion("ap-northeast-1").WithCredentials(creds),
)
fmt.Println(svc.DescribeInstances(nil))

なお、IAM Roleを利用している場合など、STSをデフォルトのセッションで利用するならば、次のようにNewCredentials関数を利用できます。

sess := session.Must(session.NewSession())
creds := stscreds.NewCredentials(sess, "arn:aws:iam::XXXXXXXXXXXX:role/role_name")
svc := ec2.New(
    sess,
    aws.NewConfig().WithRegion("ap-northeast-1").WithCredentials(creds),
)
fmt.Println(svc.DescribeInstances(nil))

まとめ

アクセスキーをハードコーディングしないでください 。 IAM Roleを利用することがベストプラクティスです。

アクセスキーを利用する場合も、基本的には デフォルトのCredentialsを利用すればほとんどのケースで対応できます 。 はじめにクレデンシャルファイルとプロファイルを利用を検討してください。 クレデンシャルファイルが利用できない場合は、環境変数でプログラム実行時に渡すのが良いでしょう。 それでも実現が難しい場合のみ、外部定義したアクセスキーをプログラムから参照します。