AccessKeyやSecretAccessKeyによる長期認証情報はセキュリティリスクが高いだろうなと感じ、AssumeRoleを使用して短期認証情報で実行する方法を調査しました。
AssumeRoleとは
AWS Security Token Service (AWS STS) を開始して、IAMユーザーやAWSリソースが、一時的に特定のIAMロールの権限を受け取ることができる機能です。
これを使うことで、IAMユーザーを多く発行せずとも、IAMユーザーやAWSリソースに権限を振ることができるようになります。
AssumeRoleを使用したsdkの実装
LoadDefaultConfigでcredential情報を取得します。
WithSharedConfigProfileオプションでIAMロールを指定します。~/.aws/configに設定したプロファイルが各ロールに対応しています。
WithAssumeRoleCredentialOptionsでAssumeRoleの設定を行います。
- config/config.go
package config
import (
"context"
"os"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
)
type Config struct {
AWSConfig *aws.Config
}
func NewConfig() *Config {
ctx := context.Background()
awsConfig, err := config.LoadDefaultConfig(
ctx,
config.WithDefaultRegion("ap-northeast-1"),
config.WithSharedConfigProfile(os.Getenv("AWS_PROFILE")),
config.WithAssumeRoleCredentialOptions(func(options *stscreds.AssumeRoleOptions) {
options.TokenProvider = func() (string, error) {
return os.Getenv("MFA_TOKEN"), nil
}
}),
)
if err != nil {
panic(err)
}
return &Config{
AWSConfig: &awsConfig,
}
}
今回は例として、S3からバケット一覧を取得するラッパーメソッドを実装します。
- s3_wrapper/s3_wrapper.go
package s3wrapper
import (
"context"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/maooz4426/aws-sdk-go-playground/config"
)
type S3Wrapper struct {
Client *s3.Client
}
func NewS3Wrapper() (*S3Wrapper, error) {
sdkConfig := config.NewConfig()
s3Client := s3.NewFromConfig(*sdkConfig.AWSConfig)
return &S3Wrapper{s3Client}, nil
}
func (s S3Wrapper) ListObject() (*s3.ListBucketsOutput, error) {
result, err := s.Client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})
if err != nil {
return nil, err
}
return result, nil
}
- main.go
package main
import (
"fmt"
"github.com/joho/godotenv"
s3wrapper "github.com/maooz4426/aws-sdk-go-playground/s3_wrapper"
)
func main() {
if err := godotenv.Load(); err != nil {
panic(err)
}
s3wrapper, err := s3wrapper.NewS3Wrapper()
if err != nil {
panic(err)
}
result, err := s3wrapper.ListObject()
if err != nil {
panic(err)
}
for _, bucket := range result.Buckets {
fmt.Println(*bucket.Name)
}
}
実行結果
MFAトークンを環境変数として渡して実行すると、以下のようにS3バケット一覧が取得できます。
❯ MFA_TOKEN=xxxxxxx go run main.go
front-test-cloudfront
pandator-assets
本番稼働した場合はどうなるのか
AssumeRoleの実装において、下記のような書き方をしていたと思います。
~/.aws/configに設定したプロファイルが各ロールに対応しています。
本番稼働の際はどのロールを使うのか気になった方がいると思いますが、本番稼働ではEC2やECSにアタッチされたインスタンスロールやタスクロールを使って実行されます。
つまり
- 開発時: ~/.aws/configで定義したプロファイル(AssumeRoleで切り替え)
- 本番時: EC2/ECSに直接アタッチされたロール(自動的にAssumeRole)
本番環境では明示的なプロファイル指定は不要になるので、環境変数でstagingやproduction環境では使わないといったコードを書くことができます。
まとめ
AssumeRoleを使うことで、わざわざアプリケーションのためにIAMユーザーとCredentialを発行せずとも実行させることが可能になります。
こうすることで安全にアプリケーションを動かせるようになるのでぜひ参考にしてみてください!