GoでSecrets Managerに保存したSlackトークンを使ってSlackへメッセージ送る
Secrets Managerに用があったのでAWS SDK for Goを使い少し触れてみました。
- AWS Secrets Managerは資格情報などの機密情報を一元的に保存、取得、アクセス制限、更新、監査、モニタリングできるサービスです。
- GoのSDKを使いSecrets Managerに保存した情報を取得して利用してみます。
お題
Slackにテストメッセージを送信する簡単なプログラムを作ります。Slackにメッセージを送信するために必要なSlackのトークン情報を事前にSecrets Managerへ保存します。プログラム実行時にSecrets Managerからトークン情報を取得してSlackへメッセージを送信します。
成果物
プログラムを実行するとメッセージが届く!それだけです!!
Secrets Managerの設定
事前準備: トークンを作成しておきます。
Slack API: Applications | Slack
シークレットキーは任意で設定します。ここで設定したシークレットキーは後々JSONをパースする際に使います。値には必要なSlackのトークンと面白みのないサンプルになりそうなのでチャンネルIDもついでに入れました。
シークレットの名前は任意で設定します。SDKで呼び出すときにここの名前を使います。
Goのサンプルコードが表示されました。エラーの処理が少し長くて端折って短くしました。
やってみた
Secrets Managerから保存したトークン情報とチャンネルIDを取得し、Slackへテストメッセージを送ります。
- AWS SDK for Goを使ってSecrets Managerに保存した値を取得します。
- Slackへのテストメッセージ送信はslack-go/slackのサンプルを流用します。
後半の説明はSecrets Managerの値を取得した際の備忘録です。
環境
> go version go version go1.15.2 darwin/amd64
コード
package main import ( "encoding/json" "fmt" "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/slack-go/slack" ) // REGION ... const REGION = "ap-northeast-1" func main() { // The name you saved in Secrets Manager secretName := "SlackInfo" // Fetch a value from the Secrets Manager secretChannelID, secretSlackToken, err := getSecret(secretName) // メモ5-1 if err != nil { log.Fatal(err) } // Send to Slack channel api := slack.New(secretSlackToken) // メモ5-2 sendMessage := "Test Message" channelID, timestamp, err := api.PostMessage(secretChannelID, slack.MsgOptionText(sendMessage, false)) // メモ5-3 if err != nil { log.Fatal(err) } fmt.Printf("Message successfully sent to channel %s at %s", channelID, timestamp) } func getSecret(sec string) (string, string, error) { // Create a Secrets Manager client svc := secretsmanager.New(session.New(), aws.NewConfig().WithRegion(REGION)) input := &secretsmanager.GetSecretValueInput{ SecretId: aws.String(sec), VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified } result, err := svc.GetSecretValue(input) if err != nil { return "", "", err } fmt.Printf("%T型\n%[1]v\n", result) // メモ1 secretString := aws.StringValue(result.SecretString) fmt.Printf("%T型\n%[1]v\n", secretString) // メモ2 res := make(map[string]interface{}) if err := json.Unmarshal([]byte(secretString), &res); err != nil { return "", "", err } fmt.Printf("%T型\n%[1]v\n", res) // メモ3 return res["channel_id"].(string), res["slack_token"].(string), nil // メモ4 }
メモ1の出力結果より
GetSecretValue
でSecrets Managerから取得した結果、GetSecretValueOutputのポインター型で返ってきました。欲しい値はSecretsString
の部分です。
*secretsmanager.GetSecretValueOutput型 { ARN: "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:SlackInfo-r5Aq3u", CreatedDate: 2020-07-24 01:34:41 +0000 UTC, Name: "SlackInfo", SecretString: "{\"channel_id\":\"xxx\",\"slack_token\":\"nnn\"}", VersionId: "790573b5-d0a0-40a2-8aa8-577dbc757bba", VersionStages: ["AWSCURRENT"] }
メモ2の出力結果より
最初はsecretString := *result.SecretString
でデリファレンスすればよいかと思いました。しかし、aws.StringValue()
で変換するほうがお行儀のよいような感じがしたのでこちらを採用。JSON形式でSecrets Managerに保存した値を取り出せました。
string型 {"channel_id":"xxx","slack_token":"nnn"}
aws - Amazon Web Services - Go SDK
メモ3の出力結果より
interface型のmapで受け取りました。メモ4でmapから値を取り出します。
map[string]interface {}型 map[channel_id:xxx slack_token:nnn]
メモ4
mapのkey
にSecrets Managerで保存したSecret key
の名前が必要になります。return
で返すときにstring
型へ変換しています。後々、Slack送信処理時にslack.New
や、PostMessage
でTokenとChannel IDを渡す際、string型で必要になりました。
return res["channel_id"].(string), res["slack_token"].(string), nil // メモ4
メモ5
secretChannelID
とsecretSlackToken
の変数にSecrets Managerで保存した値を入れることができました。あとはSlackを扱うライブラリにトークン情報と、チャネルIDを渡しているだけです。
おわりに
本職ではない上に勉強中の身ですので至らぬ点も多いかもしれません、ご了承ください。
コード書く時間よりSDKのドキュメント読むのに時間かかったのでどなたかの参考になりましたら幸いです。
最後までお読みいただきありがとうございました。
以上、コンサル部の大村@網走でした。
参考
secretsmanager - Amazon Web Services - Go SDK
Goで JSONをパースしたい時のやつ. はじめに | by taka | Medium