異なるAWSアカウントのs3からデータを取得する方法
この記事はPREVENTアドベントカレンダーの15日目の記事です。
はじめに
株式会社PREVENTの永田です。
社内で実際にあった課題とその解決方法を紹介します。
主に、解決方法として使ったs3のクロスアカウント設定の部分について書きたいと思います。
前提
AシステムとBシステムは、以下のような状況です。
- AWS Organizationでアカウントが分かれています。
- ECS Fargate上で動かしています。
課題
「Aシステムでファイルを一度ダウンロードして手動でzip化し、Bシステムにそのファイルをアップロードすることで顧客へ提出する」という作業があり、作業コストとファイルのアップロード間違いというヒューマンエラーリスクが課題となっていました。
解決方法
Aシステムでzip化したファイルをs3に保存し、Aシステムのs3のデータをBシステムから取得することで解決しました。
クロスアカウント設定について
Aシステム
IAMからs3アクセスのポリシーをアタッチしたロールを作成します。
画像ではAmazonS3FullAccessになっていますが、状況に応じて必要なs3アクセスポリシー(取得だけであれば「AmazonS3ReadOnlyAccess」だけで良いです。)をアタッチしてください。
信頼関係に、BシステムのEcsTaskRoleのarnを追加します。
フロントエンドのソースコード
s3から取得したファイルのURLとフロントエンドのoriginが一致しないため、blobに変換してからダウンロードしました。
import toast from 'react-hot-toast'
// s3から取得したファイルのURLとフロントエンドのoriginが一致しないため、blobに変換してからダウンロード
export const downloadS3FileAsBlob = (s3FileUrl: string, fileName: string) => {
fetch(s3FileUrl)
.then((response) => {
if (response.ok) return response.blob()
throw new Error('Network response was not ok.')
})
.then((fileBlob) => {
const url = window.URL.createObjectURL(fileBlob)
const a = document.createElement('a')
a.href = url
a.download = fileName
document.body.appendChild(a)
a.click()
window.URL.revokeObjectURL(url)
toast.success('ファイルのダウンロードを開始しました。')
})
.catch((error) => {
console.error(error)
})
}
Bシステム
Aシステム側で作成したroleのarnをリソースにしたポリシーを作成します。
EcsTaskRoleに上記のポリシーをアタッチします。
以上でAWS上の設定は完了です。
Bシステムのソースコード
ASystemRoleArn
に、Aシステムのarnを設定してあげることで、s3からデータ取得が可能となります。
弊社ではGolangを利用しているため、Golangのサンプルコードになります。
func NewS3ASystemRole() *s3.S3 {
var cfgs []*aws.Config
cfgs = append(cfgs, &aws.Config{
Region: aws.String("ap-northeast-1"),
})
sess, err := session.NewSession(cfgs...)
if err != nil {
log.Fatalf("Failed to create session: %s", err)
}
creds := stscreds.NewCredentials(sess, config.Conf.ASystemRoleArn)
return s3.New(sess, &aws.Config{Credentials: creds})
}
最後に
主にAWSのクロスアカウント設定について書かせていただきました。
誰かの助けになると嬉しいです。また、他に良い解決方法があれば教えていただけるとありがたいです。
Discussion