- 投稿日:2020-09-24T23:16:57+09:00
Go言語のコンパイラ、インタプリタ利用時にもTABキーで補完したいという願望を叶える方法
Go言語のコンパイラ、インタプリタ実行時にコマンドがTAB補完出来ず不便な思いをしていました。探したところ、
gocomplete
と言う拡張機能をインストールするとbash completionの様にTAB補完出来ることが分かりました。故に、利用方法を備忘録メモとして残しておこうと思います。拡張機能の入手
$ go get -u github.com/posener/complete/gocompleteインストール
$ $GOPATH/gocomplete -install Install completion for go? y Installing... Done!上記のインストールコマンドの実行により、.bash_profileにgocompleteを有効化するための情報が書き込まれます。
.bash_profileに書き込まれる情報complete -C /Users/yuhkiyano/go/bin/gocomplete go有効化
シェルを再起動するか、以下の様に.bash_profileを再読込すれば有効化されます。
$ source .bash_profileReference
- 投稿日:2020-09-24T23:16:57+09:00
Go言語向けbash completionを使いたいという願望を叶える方法
Go言語のコンパイラ、インタプリタ実行時にコマンドがTAB補完出来ず不便な思いをしていました。探したところ、
gocomplete
と言う拡張機能をインストールするとbash completionの様にTAB補完出来ることが分かりました。故に、利用方法を備忘録メモとして残しておこうと思います。拡張機能の入手
$ go get -u github.com/posener/complete/gocompleteインストール
$ $GOPATH/gocomplete -install Install completion for go? y Installing... Done!上記のインストールコマンドの実行により、.bash_profileにgocompleteを有効化するための情報が書き込まれます。
.bash_profileに書き込まれる情報complete -C /Users/yuhkiyano/go/bin/gocomplete go有効化
シェルを再起動するか、以下の様に.bash_profileを再読込すれば有効化されます。
$ source .bash_profileReference
- 投稿日:2020-09-24T18:33:32+09:00
組み合わせ爆発ハラスメントの処方箋
プログラミング初学者向けの内容です。
今のところ Golang, Ruby, Python, JavaScript, TypeScript による処方箋のみ掲載しています。ある日のこと
知人「店長からさぁ、
『うちはメニューの数が少ないから、
コンビ・メニュー作ることにした』『とりあえず、
今あるメニューを組み合わせて、
単品から全部入りまで
すべての組み合わせのリスト作ってくれ!』って、言われたんだけど…」
俺「え? それって、
???があるとしたら、
↓みたいなやつ?」1:?
2:?
3:? ?
4:?
5:? ?
6:? ?
7:? ? ?知人「そう。そう。それ!それ!」
俺「作れるけど、、
きっとものすごい数になるよ。
単品メニューって何種類くらいあんの?」知人「20種類くらいかなぁ。。
物好きな店長でしょ?!
めんどくせぇ。。」俺「…」
俺「あのさぁ、、
面倒くさいとかの次元じゃないんだけど。。」俺「0.1 mm 厚の紙を 26 回折ったら
富士山より高くなるって知ってる?」\begin{align} 0.1mm\times2^{26} &= 6,710,886.4 mm\\ &\fallingdotseq 6.7 km \end{align}知人「あ、なんか聞いたことあるかも。。」
俺「それと同じなんだけど、、」
\begin{align} 2^{20} - 1 &= 1,048,575 通り\\ &\fallingdotseq 105万通り \end{align}俺「105万通りは、
さすがにメニュー充実しすぎだろ(笑)」知人「へ〜、そんなになるんだぁ!」
俺「…」
Golang による処方箋
取り急ぎ Golang で書いてみます。
menu.gopackage main import ( "flag" "fmt" "strings" ) func comball(in []string) [][]string { n := 1 << len(in) out := make([][]string, n) for i := 0; i < n; i++ { ss := make([]string, 0, len(in)) for j := 0; j < len(in); j++ { if 1<<j&i != 0 { ss = append(ss, in[j]) } } out[i] = ss } return out } func main() { flag.Parse() args := flag.Args() for i, ss := range comball(args) { fmt.Printf("%d:%s\n", i, strings.Join(ss, " ")) } }Go のバージョンです。
version$ go version go version go1.15.2 linux/amd64
実行してみます。
実行$ go run menu.go ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txtGolang はコンパイルも実行も速くていいですね。
Generics をサポートしていないので string 型専用の関数になってしまい、そこが残念ポイントですが、LL のような感覚で気軽にいろいろ試せます。
(Generics は来年サポートされるようですね)プログラムは標準出力へ書き出すようにしましたが、そのまま出力するとたぶん大変なことになるので menu.txt という名前のファイルへリダイレクトしました。
ファイルの先頭を見てみます。
ファイルの先頭$ head menu.txt 0: 1:? 2:? 3:? ? 4:? 5:? ? 6:? ? 7:? ? ? 8:? 9:? ?最初の行に「なし」を出すようにしてます。
今度は末尾を見てみます。
ファイルの末尾$ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?1行目の「なし」を除いて、ちゃんと 104 万 8,575 行あります。
ファイルサイズが 56.4 MiB もありますが、、(笑)
(圧縮して 4 Mib くらい)
ひとまず、これで大丈夫そうです。あと、 Golang はサクッとクロスコンパイルしてシングルバイナリが作れるのがいいですね!
とりあえず、AMD64 互換 の linux と Mac と Windows 用を用意して持ち帰ってもらうことにました。build.shGOOS=linux GOARCH=amd64 go build -o ./linux-amd64/menu menu.go GOOS=darwin GOARCH=amd64 go build -o ./darwin-amd64/menu menu.go GOOS=windows GOARCH=amd64 go build -o ./windows-amd64/menu.exe menu.goでも、、
せっかくプログラムを書いてあげたのに、結局、彼は「店長に怒られそう…」という理由で、これを使ってくれませんでした。
遠い昔を思い出す
知人は採用してくれませんでしたが、これってテストデータの生成(フラグの組み合わせとか)にも応用できますよ。
昔、入社 1 年目のとき、まるで野球部の球拾いのごとくテスターをやらされた日々を思い出します。
ある日、明確なテスト仕様書もない中で、先輩 SE から無茶振りされました。
「可能な組み合わせを全部テストするなんて当たり前なの!お前バカなの!?」
と怒鳴られました。
遠い昔のことなので、細かいことはあまり良く覚えてませんが、同期の仲間と計算してみると、1 個 1 分でやったとしても、寝ずにやって何十年かかるとか、そんな途方もないオーダーでした。
現実的な解が思い浮かばなかったので、もっと上の先輩に相談しました。
すると、即答で「バカは相手にしなくていいから(笑)!」と言ってくれ、あっさりとこの問題は解決してしまいました。今考えると完全にパワハラでした。
2〜3日、真剣に悩みましたから(笑)無茶ぶりした先輩 SE はその後しばらくして会社を辞めていきました。
でも、マシンが高速化し自動テストがあたりまえになった現代では、当時できなかったいろんなことができるようになりました。
あのとき、もし今の環境が手元にあったら、この程度の簡単な処方箋であっさりと解決していたのかも。。
そう考えると感慨深いものがあります。先輩 SE が後輩を馬鹿呼ばわりすることもなく、彼がさらに上の先輩から馬鹿呼ばわりされることもなかったかもしれません。
ということで、他の言語の例もいくつか載せておきます。
Ruby で調合する
Ruby はあまり書いたことがないので、らしいコードじゃないかもしれません。
プログラムをみる
menu.rbdef comb(arr) out = [] n = 1 << arr.size n.times do |i| a = [] arr.size.times do |j| if 1 << j & i != 0 a << arr[j] end end out << a end out end comb(ARGV).each.with_index(0) do |a, i| puts i.to_s + ":" + a.join(" ") end実行$ ruby --version ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux] $ ruby menu.rb ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?まあ、Ruby の場合は組み込み関数を使えば、↓これでもいけますね。
出力順が違いますけど。。menu2.rbdef comball(arr) out = [[]] arr.each_with_index { |s, i| out += arr.combination(i+1).to_a } out end comball(ARGV).each.with_index(0) do |a, i| puts i.to_s + ":" + a.join(" ") endRuby って、書く順番がなんか他の言語と違いますよね。
この感覚が気持ちよくて好きです。。Python で調合する
プログラムをみる
menu.pyimport sys def comball(arr): out = [] n = 1 << len(arr) for i in range(n): a = [] for j in range(len(arr)): if 1 << j & i != 0: a.append(arr[j]) out.append(a) return out arr = sys.argv arr.pop(0) for i, a in enumerate(comball(arr)): s = ' '.join(a) print('{0}:{1}'.format(i, s))実行$ python3 --version Python 3.6.8 $ python3 menu.py ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?end や } が必要ない分、関数本体が短く書けますね。
JavaScript で調合する
プログラムをみる
menu.jsfunction comball(arr) { const out = [] const n = 1 << arr.length for (let i = 0; i < n; i++) { const a = [] for (let j = 0; j < arr.length; j++) { if ((1 << j & i) != 0) { a.push(arr[j]) } } out.push(a) } return out } const arr = process.argv.slice(2) comball(arr).forEach((a, i) => console.log(i + ":" + a.join(" ")) )実行$ node --version v12.16.1 $ node menu.js ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?JavaScript って & より != の方が演算子の優先順位が高いんですよね。
だから括弧が付いてます。
なんか理由があるんですかね。。TypeScript で調合する
プログラムをみる
menu.tsfunction comball<T>(arr: T[]): T[][] { const out: T[][] = [] const n = 1 << arr.length for (let i = 0; i < n; i++) { const a: T[] = [] for (let j = 0; j < arr.length; j++) { if ((1 << j & i) != 0) { a.push(arr[j]) } } out.push(a) } return out } const arr: string[] = process.argv.slice(2) comball(arr).forEach((a, i) => console.log(i + ":" + a.join(" ")) )実行$ npx ts-node --version v8.10.1 $ npx ts-node menu.ts ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?TypeScript は関数シグネチャを見れば何をしそうか分かるところが良いですね。
あと、Generics 使っています。
でも、トランスパイルが遅いところが玉に瑕です。あとがき
本稿で扱ったプログラミング言語は演算子の使い方もほとんど同じなので、みんな似たコードになりましたが、それでも言語の個性が出ている部分もあって面白かったです。
後で他の言語も追記するかもしれません。
要望があればプログラムの解説も付けるかもしれません。あと、各言語のエキスパートの方で、もっとカッコいい書き方を知ってるよ! という人は是非教えてください。
それでは!
- 投稿日:2020-09-24T10:36:20+09:00
AWSクレデンシャル情報取得のベストプラクティス(AWS SDK for Go)
はじめに
ECS(Fargate)でAWS SDK for Goを使ってAWSサービスを操作した際に、最初は勢いで作ったものの本当にこれでいいんだっけ?とモヤモヤしたことがあったので、クレデンシャル情報取得の優先順位とベストプラクティスについてまとめます。
結論
いきなりですが、下記がベストプラクティスとされる優先順位です。
詳細について後述します。1. ECSでアプリを実行している場合、タスクロール 2. EC2でアプリを実行している場合、EC2のIAMロール 3. 認証情報ファイル 4. 環境変数Sessionの生成
まず、AWSサービスを使うためのsessionを生成します。
今回はリージョンのみ指定しています。sess, err := session.NewSession(&aws.Config{ Region: aws.String("ap-northeast-1")}, )クレデンシャル情報取得の優先順位
上記のようにクレデンシャル情報の指定がない場合、以下の優先順位で認証情報を取得します。
1. 環境変数 2. 認証情報ファイル 3. EC2でアプリを実行している場合、EC2のIAMロール 4. ECSでアプリを実行している場合、タスクロールそれぞれの取得方法についての詳細です。
1.環境変数から認証情報を取得
開発作業中にローカル環境(macを想定)やAWS上のEC2インスタンスなどでまずはどの環境でもサクッと動かしたい時に有用です。
$ export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX $ export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2.認証情報ファイル
credentialsのことです。AWS CLIや他の言語のAWS SDKで利用されるもの同じです。
aws configureコマンドで作成するとデフォルトで~/.aws/credentials
に作成されます。
クレデンシャル情報について何も指定しない場合は[default]
の情報を取得します。[default] aws_access_key_id = XXXXXXXXXXXXXXXXXXXX aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX3.EC2 IAMロール
IAMロールを利用することで、EC2インスタンスの一時的なセキュリティ認証情報でAWSサービスの呼び出しを行うことができます。
クレデンシャル情報をさらすことも、手元でファイルを保管することなく、EC2インスタンスへのクレデンシャル情報の配布および管理を安全に行うことができます。4.ECS タスクロール
タスクロールを利用することで、ECSタスク上で動作するアプリが一時的なセキュリティ認証情報でAWSサービスの呼び出しを行うことができます。
EC2 IAMロールと同様にクレデンシャル情報を安全に配布・管理できます。
また、タスクの実行IAMロール
という似たような名前のロールがありますが、こちらはタスクがECRからのコンテナイメージのプルや、コンテナログをCloudWatchに発行を行うために必要なもの
です。タスクロールとは異なります。[まとめ]クレデンシャル情報取得のベストプラクティス
環境変数にクレデンシャル情報を設定してしまえばローカル環境でもAWS上の環境でも動作はしますが、アクセスキーやシークレットアクセスキーが流出するリスクがあります。
認証情報ファイルも同様です。最終的にAWS上の環境にデプロイするのであればIAMロール or タスクロールがベストプラクティスです。
以下、ベストプラクティスとされる優先順位です。1. ECSでアプリを実行している場合、タスクロール 2. EC2でアプリを実行している場合、EC2のIAMロール 3. 認証情報ファイル 4. 環境変数参考
- https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-iam-roles.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_execution_IAM_role.html
- https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
- 投稿日:2020-09-24T10:14:22+09:00
Go学習 自分用メモ
はじめに
本記事はProgate Go学習コースでの内容を箇条書きしていたものを記事化したものとなります。
ここ違うよ、とか間違ってるよ、などありましたらお気軽に編集リクエストください、泣いて喜びます。
変数の宣言
- varを使う
- var 変数名 intとかstringとか = 値
- :=で宣言可能
- :=で宣言した場合、型の違う値は入らない
- しっかり=を使って値を入れよう
条件分岐
ifを使う
if, if else, elseを使う、Railsみたいにelsと省略しないようにif hoge >= 値 { println("結果1") } if else hoge == 値 { println("結果2") } else { println("結果3") }数値の扱い
%%、||は基本
比較は==、反転で!=
不等式の扱いも基本通りswitch
お馴染みswitch文
caseの値に一致するものを返す
default常備switch 値{ case 1: println("結果1") case 2: println("結果2") case 3: println("結果3") default println("結果4") }Packageとimport
Javaみたいな感じ
importする際は""で囲む
import "fmt"
コース内で出てきたPackage
・fmt コンソールに出力できる
・math/rand ランダムな値を出力できる
・time 時間に関するあれこれfmt.Printf
出力項目内に変数を指定できる
変数化したい項目は%sを用いるfunc main(){ hoge := "hoge" fmt.Printf(変数名は"%sです",hoge) }fmt.Printf("値",a,b)のように複数指定もできる
("")の中で\nを用いることで改行ができる
printlnを用いない場合自動的に改行されないので明示してやる必要がある
※注意点
%sでは文字列、%dでは整数を代入できる
型を間違えないようにfor文
お馴染みfor文、繰り返し処理を行う
for i:=1(初期化); i<= 4(繰り返す回数); i++(カウンタ) { println("結果1") }なお、変数の初期化についてはvarで宣言ができない
:=の形しか使えないので注意有名なパッケージ
math/rand
ランダムな値を生成できるパッケージ、おみくじとか作れる
使い方はrand.lntn(乱数の幅)みたいな感じ
fmt.Println(rand.Intn(10))とすれば1~10の間で適当な数字を出してくれる
小文字のLに見えたけど、実際はIだったので見間違え注意time
時間に関するあれこれ、処理ができるパッケージ
なんと完全な乱数を生成できるらしい(完全な乱数とは)
上記のmath/randに以下一文を加えるといいとかなんとかrand.Seed(time.Now().Unix())fmt.Scan(変数名)
コンソールに入力された文字を受け取るパッケージ
fmt.Scan(&input)とするとコンソールに入った文字を認識してくれる関数の定義
これほんと便利、助かる
main 関数名(){} で定義できる
呼び出す時は関数名()でおk
同じ関数を複数回呼び出すことも可能
呼び出した関数の内容をちょろっと変えたい時は引数を使う
なお呼び出された側はquestionを受け取れるようにする必要がある
questionには変数の値を渡すことも可能
text := "そんなこと言ってないよ"って変数をhoge(text)とすることでもquestionが認識してくれる
引数は複数渡すこともできて、コンマで区切ると良い
hoge("hoge")
その場合は関数を作る時の()にquestion 型を宣言してやればいいfunc hoge(question string){ fmt.Printf("任意の値",question) }戻り値
いつもの、Go言語でもreturnを使う
returnで返ってきた値は、変数に対して関数の呼び出しを行えばおkfunc main(){ magicnum := hoge(1,"hoge") fmt.Printf(magicnum,"回目") } func hoge(num int, text string){ fmt.Printf("%sです",text) return 1 }メモリ番地の呼び出し
ポインタって表現するらしい
宣言した変数ってどの番地から呼び出してんの?というのを知りたい時に使う
呼び出し方は簡単、fmt.Println(&変数名)のようにすれば、変数の値ではなくメモリ番地を返す
なおアドレスは変数に格納できる、その際は*string型で宣言すること
hogePtr *string = &hoge
stringでつくった変数の中を編集したい時は、hogePtr = なんか とすれば良い
つまりポインタを操作すると何ができんの?って話だが、一番のメリットは変数のスコープ範囲を超えて変数の値を変えられるという点
もちろんだが、関数の宣言時に引数をポインタ型で受け取れるようにする必要があるcalculate
calculateを使った場合、受け取った変数に1を足す、元の変数の値は更新しない
ただ、ポインタを使うと元の値を更新する
calculate(a) calculate(&b)
完走して思ったこと
ポインタの扱いが初めて見るものだったのでやや難しかったが、それ以外は他言語とあまり変わらないためつまずく点はなかった
Progateでも4コースなので息抜きにやってほしい
- 投稿日:2020-09-24T08:28:08+09:00
AWSクレデンシャル情報取得のベストプラクティス(AWS SDK for Go)
はじめに
ECS(Fargate)でAWS SDK for Goを使ってAWSサービスを操作した際に、最初は勢いで作ったものの本当にこれでいいんだっけ?とモヤモヤしたことがあったので、クレデンシャル情報取得の優先順位とベストプラクティスについてまとめます。
結論
いきなりですが、下記がベストプラクティスとされる優先順位です。
詳細について後述します。1. ECSでアプリを実行している場合、タスクロール 2. EC2でアプリを実行している場合、EC2のIAMロール 3. 認証情報ファイル 4. 環境変数Sessionの生成
まず、AWSサービスを使うためのsessionを生成します。
今回はリージョンのみ指定しています。sess, err := session.NewSession(&aws.Config{ Region: aws.String("ap-northeast-1")}, )クレデンシャル情報取得の優先順位
上記のようにクレデンシャル情報の指定がない場合、以下の優先順位で認証情報を取得します。
1. 環境変数 2. 認証情報ファイル 3. EC2でアプリを実行している場合、EC2のIAMロール 4. ECSでアプリを実行している場合、タスクロールそれぞれの取得方法についての詳細です。
1.環境変数から認証情報を取得
開発作業中にローカル環境(macを想定)やAWS上のEC2インスタンスなどでまずはどの環境でもサクッと動かしたい時に有用です。
$ export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX $ export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2.認証情報ファイル
credentialsのことです。AWS CLIや他の言語のAWS SDKで利用されるもの同じです。
aws configureコマンドで作成するとデフォルトで~/.aws/credentials
に作成されます。
クレデンシャル情報について何も指定しない場合は[default]
の情報を取得します。[default] aws_access_key_id = XXXXXXXXXXXXXXXXXXXX aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX3.EC2 IAMロール
IAMロールを利用することで、EC2インスタンスの一時的なセキュリティ認証情報でAWSサービスの呼び出しを行うことができます。
クレデンシャル情報をさらすことも、手元でファイルを保管することなく、EC2インスタンスへのクレデンシャル情報の配布および管理を安全に行うことができます。4.ECS タスクロール
タスクロールを利用することで、ECSタスク上で動作するアプリが一時的なセキュリティ認証情報でAWSサービスの呼び出しを行うことができます。
EC2 IAMロールと同様にクレデンシャル情報を安全に配布・管理できます。
また、タスクの実行IAMロール
という似たような名前のロールがありますが、こちらはタスクがECRからのコンテナイメージのプルや、コンテナログをCloudWatchに発行を行うために必要なもの
です。タスクロールとは異なります。クレデンシャル情報取得のベストプラクティス
環境変数にクレデンシャル情報を設定してしまえばローカル環境でもAWS上の環境でも動作はしますが、アクセスキーやシークレットアクセスキーが流出するリスクがあります。
認証情報ファイルも同様です。最終的にAWS上の環境にデプロイするのであればIAMロール or タスクロールがベストプラクティスです。
以下、ベストプラクティスとされる優先順位です。1. ECSでアプリを実行している場合、タスクロール 2. EC2でアプリを実行している場合、EC2のIAMロール 3. 認証情報ファイル 4. 環境変数参考
- https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-iam-roles.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_execution_IAM_role.html
- https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html