Skip to content

Instantly share code, notes, and snippets.

@maybe-joe
Last active March 30, 2019 05:04
Show Gist options
  • Save maybe-joe/74bea754c37f616f1596da91b6c9c5bd to your computer and use it in GitHub Desktop.
Save maybe-joe/74bea754c37f616f1596da91b6c9c5bd to your computer and use it in GitHub Desktop.
This snippet of code downloads, decrypts, and decodes private keys and config that shouldn't be hard coded or stored in a repository.
package configuration
import (
"bytes"
"cloud.google.com/go/storage"
"context"
"encoding/base64"
"golang.org/x/oauth2/google"
cloudkms "google.golang.org/api/cloudkms/v1"
)
// This snippet of code downloads, decrypts, and decodes private keys and config
// that shouldn't be hard coded or stored in a repository.
//
// I use this for things like keys for encrpyting session cookies or private config
// reguired to create a firebase admin client.
//
// I call this code in the root main func of the project. A draw back to this method
// is it increases the time taken to restart the server during development (for me this is every file save!).
// but the benefit is once the code is deployed revoking a compromised key only requires
// a server restart once the new key is uploaded. Also I can use env variables along
// with the container environment e.g. app engine to toggle pointing the service
// at development resources or production.
//
//
// The commands below use gcloud cli to encrpyt and store json files.
//
// base64 -i service-private-key.json -o service-private-key.txt
//
// gcloud kms encrypt \
// --location=global \
// --keyring=gcp-project-id \
// --key=service-private-key \
// --plaintext-file=service-private-key.txt \
// --ciphertext-file=service-private-key.enc
//
// gsutil cp algolia.enc gs://gcp-project-id-config/
func Config(projectID, bucketName, fileObjectName, keyRing, cryptoKey string) ([]byte, error) {
ctx := context.Background()
storageClient, err := storage.NewClient(ctx)
if err != nil {
return nil, err
}
bucket := storageClient.Bucket(bucketName)
fileObject := bucket.Object(fileObjectName)
reader, err := fileObject.NewReader(ctx)
if err != nil {
return nil, err
}
buffer := new(bytes.Buffer)
buffer.ReadFrom(reader)
reader.Close()
key := "projects/" + projectID + "/locations/global/keyRings/" + keyRing + "/cryptoKeys/" + cryptoKey
ciphertext := buffer.Bytes()
defaultClient, err := google.DefaultClient(ctx, cloudkms.CloudPlatformScope)
if err != nil {
return nil, err
}
cloudkmsService, err := cloudkms.New(defaultClient)
if err != nil {
return nil, err
}
req := &cloudkms.DecryptRequest{
Ciphertext: base64.StdEncoding.EncodeToString(ciphertext),
}
response, err := cloudkmsService.Projects.Locations.KeyRings.CryptoKeys.Decrypt(key, req).Do()
if err != nil {
return nil, err
}
content, err := base64.StdEncoding.DecodeString(response.Plaintext)
if err != nil {
return nil, err
}
blob, err := base64.StdEncoding.DecodeString(string(content))
if err != nil {
return nil, err
}
return blob, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment