1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Go] Cloud OS Login APIを使ってComputeEngineにサービスアカウントのユーザーを作成する

Last updated at Posted at 2022-11-15

あまり探してもサンプルコードはドキュメントが発見できなかったためメモ
いい感じに使って下さい

package main

import (
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"log"
	"os"
	"time"

	oslogin "cloud.google.com/go/oslogin/apiv1"
	"cloud.google.com/go/oslogin/apiv1/osloginpb"
	"golang.org/x/crypto/ssh"
	"google.golang.org/api/option"
	"google.golang.org/genproto/googleapis/cloud/oslogin/common"
)

// generatePrivateKey 指定したビットサイズで秘密鍵を作成する
func generatePrivateKey(bitSize int) (*rsa.PrivateKey, error) {
	// Private Key generation
	privateKey, err := rsa.GenerateKey(rand.Reader, bitSize)
	if err != nil {
		return nil, err
	}

	// Validate Private Key
	err = privateKey.Validate()
	if err != nil {
		return nil, err
	}

	return privateKey, nil
}

// generatePublicKey 秘密鍵から公開鍵を生成する
func generatePublicKey(privatekey *rsa.PublicKey) ([]byte, error) {
	publicRsaKey, err := ssh.NewPublicKey(privatekey)
	if err != nil {
		return nil, err
	}

	pubKeyBytes := ssh.MarshalAuthorizedKey(publicRsaKey)

	// Remove last element(newline)
	return pubKeyBytes[:len(pubKeyBytes)-1], nil
}

// encodePrivateKeyToPEM 秘密鍵をRSAからPEMへ変換する
func encodePrivateKeyToPEM(privateKey *rsa.PrivateKey) []byte {
	// Get ASN.1 DER format
	privDER := x509.MarshalPKCS1PrivateKey(privateKey)

	// pem.Block
	privBlock := pem.Block{
		Type:    "RSA PRIVATE KEY",
		Headers: nil,
		Bytes:   privDER,
	}

	// Private key in PEM format
	privatePEM := pem.EncodeToMemory(&privBlock)

	return privatePEM
}

// writePemToFile 鍵を書き込む
func writeKeyToFile(keyBytes []byte, saveFileTo string) error {
	err := os.WriteFile(saveFileTo, keyBytes, 0600)
	if err != nil {
		return err
	}
	return nil
}

func main() {
	// contextの生成
	ctx := context.Background()

	// クライアント作成
	ols, err := oslogin.NewClient(ctx)
	if err != nil {
		log.Fatal(err)
	}
	// 一応deferしてるけど、Fatalの場合動かないと思う 本番で使う場合治してね
	defer ols.Close()

	// SSH用の鍵の生成 お好みでビットサイズを調整
	pvtKey, err := generatePrivateKey(1024)
	if err != nil {
		log.Fatal(err)
	}
	pk := encodePrivateKeyToPEM(pvtKey)
	log.Println("generated private key:", string(pk))

	pubKey, err := generatePublicKey(&pvtKey.PublicKey)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("generated public key:", string(pubKey))

	// 秘密鍵の書き込み
	err = writeKeyToFile(pk, "./id_rsa")
	if err != nil {
		log.Fatal(err)
	}

	// 公開鍵の書き込み
	err = writeKeyToFile(pubKey, "./id_rsa_test.pub")
	if err != nil {
		log.Fatal(err)
	}

	// sshキーを読み込ませる
	// parent は"users/{サービスアカウントのmail の形式で入力する}
	parent := "users/compute-engine-user@project-id-xxxxxxxxxxxxxxxxxxxxx.iam.gserviceaccount.com"
	projectID := "yourproject-xxxxx"
	exp := time.Now().Add(6 * time.Hour)
	log.Println("Your key will be expires at", exp)
	is, err := ols.ImportSshPublicKey(ctx, &osloginpb.ImportSshPublicKeyRequest{
		Parent: parent,
		SshPublicKey: &common.SshPublicKey{
			Key:                string(pubKey),
			ExpirationTimeUsec: exp.UnixNano(),
		},
		ProjectId: projectID,
	})
	if err != nil {
		log.Fatalln("is err:", err)
	}
	log.Println("is:", is)
}

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?