1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Github Actions Secrets API を使って Go で Secrets を更新する

Github Actions API が公開され、 Secrets を API 経由で更新できるようになりました

Github Actions で利用する Secrets はこれまで手作業で更新する必要がありました。
たくさんのレポジトリを管理していてそれぞれに Actions を仕込むときに更新がとても大変でした。

そんな中、 Github Actions API が公開(2020/1/27)され、 Secrets の更新が API 経由で行えるようになりました :tada:

Secrets | Github Developer Guide

Secrets API の概要

Secrets は秘密鍵、公開鍵を用いて暗号化しているのですが、 Github Actions では libsodium を使って実現しているようです。

github_secrets-100.jpg

  • 暗号化に使う公開鍵を Github Actions API を使って取得します。
  • key_id と key が取得できます。 (libsodium で Secrets を暗号化するための公開鍵です)
    • key は base64 でエンコードされているのでデコードしてバイナリに戻します。
  • 公開鍵を用いて Secrets を暗号化します。
  • Github Actions API を使って Secrets 名と暗号化された Secrets を送信します。
  • Github Actions で用いるときに秘密鍵で復号化して Secrets を利用しているものと思われます。

Go で API を叩いてみます

Go には google/go-github という Github API のライブラリが存在します。

google/go-github - Github

ただ、 2020/1/31 現在、まだこのライブラリでは Github Actions API をサポートしてない模様です。
調べてみると、既にサポート PR が出ていたので試してみました。

go.mod
replace github.com/google/go-github/v29 => github.com/martinssipenko/go-github/v29 v29.0.3-0.20200130054045-bbe3d535861d
func UpdateSecret(owner, repo, name, secret string) error {
    // Github Client を用意
    sts := oauth2.StaticTokenSource(
        &oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
    )
    oc := oauth2.NewClient(context.Background(), sts)
    cli := github.NewClient(oc)

    // 公開鍵を取得
    pubKey, _, err := cli.Actions.GetPublicKey(context.Background(), owner, repo)
    if err != nil {
        fmt.Println("error GetPublicKey:", err.Error())
        return err
    }
    pkBase64 := pubKey.GetKey()
    pk := make([]byte, 32)
    _, err = base64.StdEncoding.Decode(pk, []byte(pkBase64))
    if err != nil {
        fmt.Println("base64 decode error:", pkBase64, err.Error())
        return err
    }

    // sodium で暗号化を施す
    encSec := sodium.Bytes(secret).SealedBox(sodium.BoxPublicKey{Bytes: pk})
    encSecBase64 := base64.StdEncoding.EncodeToString(encSec)

    // Secret を更新
    es := &github.EncryptedSecret{
        Name:           name,
        KeyID:          *pubKey.KeyID,
        EncryptedValue: encSecBase64,
    }
    _, err = cli.Actions.CreateOrUpdateSecret(context.Background(), owner, repo, es)
    if err != nil {
        fmt.Println("failed to update secret", err.Error())
        return err
    }
    return nil
}

これで無事 Secret を API 経由で更新できました :tada:

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?