Giter Site home page Giter Site logo

googlecloudplatform / berglas Goto Github PK

View Code? Open in Web Editor NEW
1.2K 28.0 99.0 6.85 MB

A tool for managing secrets on Google Cloud

Home Page: https://cloud.google.com/secret-manager

License: Apache License 2.0

Dockerfile 0.09% Makefile 0.08% Go 99.83%
google-cloud gsecrets secrets-management secret-management google-cloud-storage google-cloud-kms

berglas's Introduction

Berglas

Build Status GoDoc

Berglas Logo

Berglas is a command line tool and library for storing and retrieving secrets on Google Cloud. Secrets are encrypted with Cloud KMS and stored in Cloud Storage. An interoperable layer also exists with Secret Manager.

  • As a CLI, berglas automates the process of encrypting, decrypting, and storing data on Google Cloud.

  • As a library, berglas automates the inclusion of secrets into various Google Cloud runtimes.

Berglas is not an officially supported Google product.

Setup

Prerequisites

  1. Install the Cloud SDK for your operating system. Alternatively, you can run these commands from Cloud Shell, which has the SDK and other popular tools pre-installed.

    If you are running from your local machine, you also need Default Application Credentials:

    gcloud auth application-default login
    

    This will open a web browser and prompt for a login to your Google account. On headless devices, you will need to create a service account. For more information, please see the authentication section.

  2. Install the berglas CLI using one of the following methods:

    • Install a pre-compiled binary for your operating system from the latest releases.

    • Use an official Docker container:

      docker run -it us-docker.pkg.dev/berglas/berglas/berglas
      

      Note: older Docker container images are available on Container Registry and Artifact Registry, but new versions are not published there.

    • Use Homebrew on macOS:

      brew install berglas

      Note: sometimes the Homebrew formula can be several versions behind.

    • Install from source (requires a working Go installation):

      go install github.com/GoogleCloudPlatform/berglas/v2@latest
  3. Export your project ID as an environment variable. The rest of this setup guide assumes this environment variable is set:

    export PROJECT_ID=my-gcp-project-id
    

    Please note, this is the project ID, not the project name or project number. You can find the project ID by running gcloud projects list or in the web UI.

Secret Manager Storage

  1. Enable required services on the project:

    gcloud services enable --project ${PROJECT_ID} \
      secretmanager.googleapis.com
    

Cloud Storage Storage

  1. Export your desired Cloud Storage bucket name. The rest of this setup guide assumes this environment variable is set:

    export BUCKET_ID=my-secrets
    

    Replace my-secrets with the name of your bucket. Set only the name, without the gs:// prefix. This bucket should not exist yet!

  2. Enable required services on the project:

    gcloud services enable --project ${PROJECT_ID} \
      cloudkms.googleapis.com \
      storage-api.googleapis.com \
      storage-component.googleapis.com
    
  3. Bootstrap a Berglas environment. This will create a new Cloud Storage bucket for storing secrets and a Cloud KMS key for encrypting data.

    berglas bootstrap --project $PROJECT_ID --bucket $BUCKET_ID
    

    This command uses the default values. You can customize the storage bucket and KMS key configuration using the optional flags. Run berglas bootstrap -h for more details.

    If you want full control over the creation of the Cloud Storage and Cloud KMS keys, please see the custom setup documentation.

  4. (Optional) Bootstrap a Berglas environment specifying a bucket location. By default the berglas bucket is created in the multi-regional location US. You can specify your location by using the following command. Please see the list of supported locations in the GCP bucket location documentation page

    export BUCKET_LOCATION=europe-west1
    berglas bootstrap \
      --project $PROJECT_ID \
      --bucket $BUCKET_ID \
      --bucket-location $BUCKET_LOCATION
    

    This command uses the default values. You can customize the storage bucket and KMS key configuration using the optional flags. Run berglas bootstrap -h for more details.

    If you want full control over the creation of the Cloud Storage and Cloud KMS keys, please see the custom setup documentation.

  5. (Optional) Enable Cloud Audit logging on the bucket:

    Please note this will enable audit logging on all Cloud KMS keys and all Cloud Storage buckets in the project, which may incur additional costs.

    1. Download the exiting project IAM policy:

      gcloud projects get-iam-policy ${PROJECT_ID} > policy.yaml
      
    2. Add Cloud Audit logging for Cloud KMS and Cloud Storage:

      cat <<EOF >> policy.yaml
      auditConfigs:
      - auditLogConfigs:
        - logType: DATA_READ
        - logType: ADMIN_READ
        - logType: DATA_WRITE
        service: cloudkms.googleapis.com
      - auditLogConfigs:
        - logType: ADMIN_READ
        - logType: DATA_READ
        - logType: DATA_WRITE
        service: storage.googleapis.com
      EOF
      
    3. Submit the new policy:

      gcloud projects set-iam-policy ${PROJECT_ID} policy.yaml
      
    4. Remove the updated policy from local disk:

      rm policy.yaml
      

CLI Usage

  1. Create a secret:

    Using Secret Manager storage:

    berglas create sm://${PROJECT_ID}/foo my-secret-data
    

    Using Cloud Storage storage:

    berglas create ${BUCKET_ID}/foo my-secret-data \
      --key projects/${PROJECT_ID}/locations/global/keyRings/berglas/cryptoKeys/berglas-key
    
  2. Grant access to a secret:

    Using Secret Manager storage:

    berglas grant sm://${PROJECT_ID}/foo --member user:[email protected]
    

    Using Cloud Storage storage:

    berglas grant ${BUCKET_ID}/foo --member user:[email protected]
    
  3. Access a secret's data:

    Using Secret Manager storage:

    berglas access sm://${PROJECT_ID}/foo
    my-secret-data
    

    Using Cloud Storage storage:

    berglas access ${BUCKET_ID}/foo
    my-secret-data
    
  4. Spawn a child process with secrets populated in the child's environment:

    berglas exec -- myapp --flag-a --flag-b
    

    This will spawn myapp with an environment parsed by berglas.

  5. Access data from a specific version/generation of a secret:

    Using Secret Manager storage:

    berglas access sm://${PROJECT_ID}/foo#1
    my-previous-secret-data
    

    Using Cloud Storage storage:

    berglas access ${BUCKET_ID}/foo#1563925940580201
    my-previous-secret-data
    
  6. Revoke access to a secret:

    Using Secret Manager storage:

    berglas revoke sm://${PROJECT_ID}/foo --member user:[email protected]
    my-previous-secret-data
    

    Using Cloud Storage storage:

    berglas revoke ${BUCKET_ID}/foo --member user:[email protected]
    
  7. Delete a secret:

    Using Secret Manager storage:

    berglas delete sm://${PROJECT_ID}/foo
    

    Using Cloud Storage storage:

    berglas delete ${BUCKET_ID}/foo
    

In addition to standard Unix exit codes, if the CLI exits with a known error, Berglas will exit with one of the following:

  • 60 - API error. Berglas got a bad response when communicating with an upstream API.

  • 61 - Misuse error. You gave unexpected input or behavior. Please read the error message. Open an issue if you think this is a mistake.

The only exception is berglas exec, which will exit with the exit status of its child command, if one was provided.

Integrations

  • App Engine (Flex) - When invoked via App Engine Flex, Berglas resolves environment variables to their plaintext values using the `berglas://reference syntax. This integration works with any language runtime because berglas serves as the entrypoint to the Docker container.

  • App Engine (Standard) - When invoked via App Engine, Berglas resolves environment variables to their plaintext values using the berglas://reference syntax. This integration only works with the Go language runtime because it requires importing the auto/ package.

  • Cloud Run - When invoked via Cloud Run, Berglas resolves environment variables to their plaintext values using the berglas:// reference syntax. This integration works with any language runtime because berglas serves as the entrypoint to the Docker container.

  • Cloud Functions - When invoked via Cloud Functions, Berglas resolves environment variables to their plaintext values using the berglas:// reference syntax. This integration only works with the Go language runtime because it requires importing the auto/ package.

  • Cloud Build - When invoked via Cloud Build, Berglas resolves environment variables to plaintext values using the berglas:// reference syntax. This integration only works with volume mounts, so all Berglas secrets need to specify the ?destination parameter.

  • Kubernetes - Kubernetes pods can consume Berglas secrets by installing a MutatingWebhook. This webhook mutates incoming pods with the berglas:// reference syntax in environment references to resolve at runtime. This integration works with any container, but all pods requesting berglas secrets must set an command in their Kubernetes manifests.

  • Anything - Wrap any process with berglas exec -- and Berglas will parse any local environment variables with the berglas:// reference syntax and spawn your app as a subprocess with the plaintext environment replaced.

Logging

Both the berglas CLI and berglas library support debug-style logging. This logging is off by default because it adds additional overhead and logs information that may be security-sensitive.

The default logging behavior for the berglas CLI is "text" (it can be changed with the --log-format flag). The default logging behavior for the berglas library is structured JSON which integrates well with Cloud Logging (it can be changed to any valid formatter and you can even inject your own logger).

Library Usage

Berglas is also a Go library that can be imported in Go projects:

import (
	_ "github.com/GoogleCloudPlatform/berglas/v2/pkg/auto"
)

When imported, the berglas package will:

  1. Download and decrypt any secrets that match the Berglas environment variable reference syntax in the environment.

  2. Replace the value for the environment variable with the decrypted secret.

You can also opt out of auto-parsing and call the library yourself instead:

import (
	"context"
	"log"
	"os"

	"github.com/GoogleCloudPlatform/berglas/v2/pkg/berglas"
)

func main() {
	ctx := context.Background()

	// This higher-level API parses the secret reference at the specified
	// environment variable, downloads and decrypts the secret, and replaces the
	// contents of the given environment variable with the secret result.
	if err := berglas.Replace(ctx, "MY_SECRET"); err != nil {
		log.Fatal(err)
	}

	// This lower-level API parses the secret reference, downloads and decrypts
	// the secret, and returns the result. This is useful if you need to mutate
	// the result.
	if v := os.Getenv("MY_SECRET"); v != "" {
		plaintext, err := berglas.Resolve(ctx, v)
		if err != nil {
			log.Fatal(err)
		}
		os.Unsetenv("MY_SECRET")
		os.Setenv("MY_OTHER_SECRET", string(plaintext))
	}
}

For more examples and documentation, please see the godoc.

Authentication

By default, Berglas uses Google Cloud Default Application Credentials. If you have gcloud installed locally, ensure you have application default credentials:

gcloud auth application-default login

On GCP services (like Cloud Build, Compute, etc), it will use the service account attached to the resource.

To use a specific service account, set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the filepath to the JSON file where your credentials reside on disk:

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json

To learn more, please see the Google Cloud Service Account documentation.

Authorization

To control who or what has access to a secret, use berglas grant and berglas revoke commands. These methods use Cloud IAM internally. Any service account or entity using Berglas will need to authorize using the cloud-platform scope.

Secret Manager Storage

Creating a secret requires roles/secretmanager.admin on Secret Manager in the project.

Accessing a secret requires roles/secretmanager.secretAccessor on the secret in Secret Manager.

Deleting a secret requires roles/secretmanager.admin on Secret Manager in the project.

Cloud Storage Storage

Creating a secret requires roles/storage.objectCreator on the Cloud Storage bucket and roles/cloudkms.cryptoKeyEncrypter on the Cloud KMS key.

Accessing a secret requires roles/storage.objectViewer on the Cloud Storage bucket and roles/cloudkms.cryptoKeyDecrypter on the Cloud KMS key.

Deleting a secret requires roles/storage.objectAdmin on the Cloud Storage bucket.

Implementation

Secret Manager Storage

This section describes the Secret Manager implementation. This knowledge is not required to use Berglas, but it is included for security-conscious/curious users who want to learn about how Berglas works internally to build a threat model.

  1. Berglas calls the Secret Manager API directly for all operations.

Cloud Storage Storage

This section describes the Cloud Storage implementation. This knowledge is not required to use Berglas, but it is included for security-conscious/curious users who want to learn about how Berglas works internally to build a threat model.

When encrypting a secret:

  1. Berglas generates an AES-256-GCM data encryption key (DEK) using Go's crypto package for each secret. (N.B. each secret has its own, unique DEK).

  2. Berglas encrypts the plaintext data using the locally-generated DEK, producing encrypted ciphertext, prepended with the AES-GCM nonce.

  3. Berglas encrypts the DEK using the specified Cloud KMS key, also known as a key encryption key (KEK). This process is called envelope encryption.

  4. Berglas stores the Cloud KMS key name, encrypted DEK, and encrypted ciphertext as a single blob in Cloud Storage.

When decrypting a secret:

  1. Berglas downloads the blob from Cloud Storage and separates the Cloud KMS key name, encrypted DEK, and ciphertext out of the blob.

  2. Berglas decrypts the DEK using Cloud KMS. This is part of envelope encryption.

  3. Berglas decrypts the ciphertext data locally using the decrypted DEK.

Security & Threat Model

See the security and threat model.

FAQ

Q: Should I use Berglas or Secret Manager?
Berglas is compatible with Secret Manager and offers convenience wrappers around managing secrets regardless of whether they reside in Cloud Storage or Secret Manager. New projects should investigate using Secret Manager directly as it has less operational overhead and complexity, but Berglas will continue to support Cloud Storage + Cloud KMS secrets.

Q: Is there a size limit on the data I can encrypt?
Berglas is targeted at application secrets like certificates, passwords, and API keys. While its possible to encrypt larger binary files like PDFs or images, Berglas uses a a GCM cipher mode to encrypt data, meaning the data must fit in memory and is limited to 64GiB.

Q: Why do you use envelope encryption instead of encrypting the data directly with Cloud KMS?
Envelope encryption allows for encrypting the data at the application layer, and it enables encryption of larger payloads, since Cloud KMS has a limit on the size of the payload it can encrypt. By using envelope encryption, Cloud KMS always encrypts a fixed size data (the AES-256-GCM key). This saves bandwidth (since large payloads are encrypted locally) and increases the size of the data which can be encrypted.

Q: Why does Berglas need permission to view my GCP resource?
Berglas communicates with the API to read the environment variables that were set on the resource at deploy time. Otherwise, a package could inject arbitrary environment variables in the Berglas format during application boot.

Q: I renamed a secret in Cloud Storage and now it fails to decrypt - why?
Berglas encrypts secrets with additional authenticated data including the name of the secret. This reduces the chance an attacker can escalate privilege by convincing someone to rename a secret so they can gain access.

Q: Why is it named Berglas?
Berglas is a famous magician who is best known for his secrets.

Contributing

Please see the contributing guidelines.

License

This library is licensed under Apache 2.0. Full license text is available in LICENSE.

berglas's People

Contributors

bfallik avatar christopherl91 avatar corneliusweig avatar dariusch avatar dependabot[bot] avatar dp-rufus avatar glasnt avatar guillaumeblaquiere avatar indigolain avatar jm2 avatar junichisugiura avatar karthikraobr avatar kevinsimper avatar leo-baltus avatar maroux avatar martijnnpo avatar nklmilojevic avatar orthros avatar owulveryck avatar ryunen344 avatar sbedford avatar sethvargo avatar sinmetal avatar ulsa avatar wmuizelaar avatar wojcikm avatar yfuruyama avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

berglas's Issues

Overwriting a secret resets permissions?

This may be related to #40, I'm not sure. Regardless, I'm experiencing the following:

  1. Get data to be stored in secret(s) (in my case, the TLS private key and certificate for a DNS entry)
  2. Create secrets
  3. Grant the relevant service account for the hosts which the DNS resolves to access to those secrets, via berglas grant
  4. Rotate the secrets (i.e. TLS cert is due to expire, so generate a new private key and get a new cert for it, then use berglas create to overwrite the existing key/cert with the new ones)
  5. All 'grants' for the objects in GCS are missing, and have to be reissued

When an object already exists and I have the permissions to overwrite it with a new version I would expect the IAM permissions created as a result of the prior berglas grant call to be retained.

If this is an explicit expectation of create for security purposes or similar I would expect the edit functionality described in #40 to retain grants (I didn't manage to spot anything in the modifications of that PR that does this).

Or have I somehow managed to create a completely barmy GCS bucket that is behaving in an unexpected way? I tested using gsutil cp and verified that that is also not retaining the object permissions or metadata when a version of the object already exists, which surprised me.

bucket policy only - is it supported?

Hi,

I'm trying to get some things working with berglas, but in my organization policy it is stated that ACLs aren't allowed anymore, just IAM on buckets (see https://cloud.google.com/storage/docs/bucket-policy-only)

The documentation of berglas talks about IAM as well, but it seems like when I'm trying to give my own account (which is owner on the project) read permissions, it failes with the following error message:

$ berglas grant berglas-goingontheroad-nl/wordpress-db-user --member [email protected]
failed to get Storage IAM policy: googleapi: Error 400: Object policies are disabled for bucket 'berglas-goingontheroad-nl' when Bucket Policy Only is enabled. Read more at https://cloud.google.com/storage/docs/bucket-policy-only., invalid

Is this a bug, or is it intentional that berglas requires per object ACLs?

Thanks,

Wietse

UI Support

UI support would be awesome. Each user can deploy into either GAE or GKE.

Cloud Run example assumes default service account

"Get the Cloud Run service account email" is assuming the default compute service account is used as service account of the cloud run service.
Users can customize it, it is actually recommended that they do.

You should instead describe the service and extract the service account

failed to create KMS crypto key berglas-key

I tried to bootstrap a new setup. Then I got an error that the kms rotation period is not correct.

$ git rev-parse HEAD                                                               
d6b103a70c7b62989864d1dfec36213bf99eaa0c
$ GO111MODULE=on go run main.go bootstrap --project $PROJECT_ID --bucket $BUCKET_ID
failed to create KMS crypto key berglas-key: rpc error: code = InvalidArgument desc = Invalid rotation period.
exit status 1

The same happens with the latest available binary.

Any ideas?

Problem after revoking access to a secret

Hi,

First, thanks for this awesome tool !

I got an issue when I revoke access to a user on a given secret.
If this user has been granted access to others secrets we got a permission denied on KMS decrypt resource.

Here what I try

  1. Create 2 secrets
berglas create sku-berglas_secrets/sku/test/secret1 1234 --key projects/sku-berglas/locations/global/keyRings/berglas/cryptoKeys/berglas-key

berglas create sku-berglas_secrets/sku/test/secret2 5678 --key projects/sku-berglas/locations/global/keyRings/berglas/cryptoKeys/berglas-key
  1. Grant access to these secrets
berglas grant sku-berglas_secrets/sku/test/secret1 --member serviceAccount:[email protected]

berglas grant sku-berglas_secrets/sku/test/secret2 --member serviceAccount:[email protected]
  1. Revoke access on secret2
berglas revoke sku-berglas_secrets/sku/test/secret2 --member serviceAccount:[email protected]
  1. Access to secret1
berglas access sku-berglas_secrets/sku/test/secret1

I've got the following error

failed to access secret: failed to decrypt dek: rpc error: code = PermissionDenied desc = Permission 'cloudkms.cryptoKeyVersions.useToDecrypt' denied on resource 'projects/proximis-berglas/locations/global/keyRings/berglas/cryptoKeys/berglas-key' (or it may not exist).

I look into code and in GCP console, and what I understand :

  • berglas revoke operation will remove the role roles/cloudkms.cryptoKeyDecrypter for the given user but it doesn't take care if the same user has other granted secrets.
    • so decryption for theses secrets will fail.

Revoke access with cloud computing

I gave access to the SA as per the example and it was working fine, meaning able to get the secret using berglas access ${BUCKET_ID}/foo

Now, when I revoke the access for the same SA and again try to get the secret, I am able to get the response, which should not be the case and should have been a Permission Denied error.

Also, if there is no access defined, meaning when I put the secret and try to access it I get the unencrypted access. Shouldn't the secret be always protected and only accessible by the SA or member whom we add using the berglas grant ${BUCKET_ID}/foo --member * command ?

Berglas + Ruby GAE Flexible

Hi - I'm running a Rails app on GAE Flexible - Ruby. I'd prefer not to write my own Dockerfile just so I can use Berglas. Is there any way to use Berglas with GAE Flexible - Ruby out of the box, without writing a Dockerfile?

panic when creating secret on berglas bucket with wrong permissions

Steps to reproduce

  1. Create a berglas bucket (my service account doesn't have list/write/read roles to the newly created berglas bucket)
  2. Attempt to create a berglas secret using berglas cli
➜  project-x git:(master) ✗ berglas create gs://<berglas-bucket>/database-username jonny \
--key projects/<project-id>/locations/global/keyRings/<key-ring>/cryptoKeys/<key-name>
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x152db8b]
goroutine 1 [running]:
github.com/GoogleCloudPlatform/berglas/pkg/berglas.secretFromAttrs(...)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/berglas.go:123
github.com/GoogleCloudPlatform/berglas/pkg/berglas.(*Client).encryptAndWrite(0xc0002e2000, 0x17ef480, 0xc0001aa9c0, 0x7ffeefbff944, 0x14, 0x7ffeefbff959, 0x24, 0x7ffeefbff98d, 0x4e, 0xc0001a2610, ...)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/writer.go:110 +0x96b
github.com/GoogleCloudPlatform/berglas/pkg/berglas.(*Client).Create(0xc0002e2000, 0x17ef480, 0xc0001aa9c0, 0xc00022bcc8, 0x1, 0xc0002e2000, 0x0)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/create.go:75 +0xe7
github.com/GoogleCloudPlatform/berglas/pkg/berglas.Create(0x17ef480, 0xc0001aa9c0, 0xc00022bcc8, 0x8, 0x8, 0x0)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/create.go:30 +0xa2
main.createRun(0x1c25fe0, 0xc0001aa980, 0x2, 0x4, 0x0, 0x0)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/main.go:500 +0x285
github.com/spf13/cobra.(*Command).execute(0x1c25fe0, 0xc0001aa940, 0x4, 0x4, 0x1c25fe0, 0xc0001aa940)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/pkg/mod/github.com/spf13/[email protected]/command.go:826 +0x460
github.com/spf13/cobra.(*Command).ExecuteC(0x1c25360, 0x1c2ef20, 0x1708409, 0x3)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/pkg/mod/github.com/spf13/[email protected]/command.go:914 +0x2fb
github.com/spf13/cobra.(*Command).Execute(...)
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/pkg/mod/github.com/spf13/[email protected]/command.go:864
main.main()
	/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/main.go:422 +0xb88

Possible Causes

I get a panic error most likely because whenever attempting to write to the bucket I don't have necessary permissions. This is most likely due to the fact that there are two error branches that are not being checked

https://github.com/GoogleCloudPlatform/berglas/blob/master/pkg/berglas/writer.go#L97-L107

		if terr, ok := err.(*googleapi.Error); ok {
			switch terr.Code {
			case http.StatusNotFound:
				return nil, errors.New("bucket does not exist")
			case http.StatusPreconditionFailed:
				if conds.DoesNotExist {
					return nil, errSecretAlreadyExists
				}
				return nil, errSecretModified
                         /** default: // other error codes are not being checked */
			}
		} /** else { // Non-google error is not checked } */

[Idea] Terraform provider

Use cases

  1. Create secrets
  2. Retrieve secrets
resource "berglas_secret" "foo" {
  data = "my-secret-data"
  uri  = "gs://bucket/path"
  key  = "projects/PROJECT_ID/locations/global/keyRings/berglas/cryptoKeys/berglas-key"
}

Add some retries to prevent crashlooping

Some systems like Istio will not make networking available during the first few milliseconds (istio/istio#9454).

Therefore a code path executed (i.e. pkg auto) in initialization of a program is likely to fail using networking on Istio (especially more prevalent in "fast" languages like Go where process/runtime start overhead is low).

It would be great to say Berglas to retry N times with M ms intervals.

403 while deploying the go example on Cloudrun GKE

Hi,

I'm trying to deploy the go example on Cloudrun on GKE and I'm getting this error :

panic: failed to resolve environment variables: failed to find environment variables: failed to communicate with cloud run: {
  "error": {
    "code": 403,
    "message": "Request had insufficient authentication scopes.",
    "status": "PERMISSION_DENIED"
  }

The only command that is different from the README is the gcloud deploy command :

gcloud beta run deploy berglas-example-go \
  --project ${PROJECT_ID} \
  --platform gke \
  --namespace knative-serving \
  --cluster my-cluster \
  --region europe-west4 \
  --image gcr.io/${PROJECT_ID}/berglas-example-go:0.0.1 \
  --memory 1G \
  --concurrency 10 \
  --set-env-vars "API_KEY=berglas://${BUCKET_ID}/api-key,TLS_KEY=berglas://${BUCKET_ID}/tls-key?destination=tempfile"

Not that I had to remove the --allow-unauthenticated flag from the deploy command as it is not supported on GKE.

panic: /debug/requests is already registered

panic: /debug/requests is already registered. You may have two independent copies of golang.org/x/net/trace in your binary, trying to maintain separate state. This may involve a vendored copy of golang.org/x/net/trace.

goroutine 1 [running]:
golang.org/x/net/trace.init.0()
/data/develop/go/goprojects/src/golang.org/x/net/trace/trace.go:123
+0x428

This happen to me when i try to use berglas with other google lib to access the IAM api.

`berglas exec` seems to promote a bad pattern

Passing secrets as environment variables is a deprecated pattern for sensitive information (https://www.sethvargo.com/secrets-in-serverless/ or https://github.com/ahmetb/cloud-run-faq#how-to-configure-secrets-for-cloud-run-applications). However, berglas offers a sub-command exec which decrypts keys from the bucket and makes those available as environment variables to the child application:

berglas/main.go

Lines 711 to 715 in d9641d9

cmd := exec.Command(execCmd, execArgs...)
cmd.Stdin = stdin
cmd.Stdout = stdout
cmd.Stderr = stderr
cmd.Env = env

This seems to suffer from the same drawbacks as having secrets in plain text environment variables. Is my understanding correct about this? If so, I think it would be better if the documentation for berglas exec would point out that this is no water-proof approach.

GAE Flex permission denied on decrypt

I've set up Berglas as well as the various IAM settings outlined in the Flex example README (using the flex service account), but when deploying I still get the following error:

failed to access secret BUCKET_ID/my-secret: failed to access secret: failed to decrypt dek: rpc error: code = PermissionDenied desc = Permission 'cloudkms.cryptoKeyVersions.useToDecrypt' denied for resource 'projects/MY_PROJECT/locations/global/keyRings/my_key_ring/cryptoKeys/my_key'.

I've issued the gcloud kms keys add-iam-policy-binding command with --member service-PROJECT_NUMBER@gae-api-prod.google.com.iam.gserviceaccount.com assigned to the role --role roles/cloudkms.cryptoKeyEncrypterDecrypter, but still to no avail.

Any ideas or insights? Thanks!

Cloud Run requires run.viewer role for a custom service account

Hi Team,

Cloud Run examples include step

  1. Grant the service account access to read the Cloud Run deployment's environment variables:

Could you clarify why this is needed by Cloud Run? (I initially asked on the alpha-testers forum, but they suggested I'd ask here instead).

The reason I'm asking is, we'd like to limit the permissions for the Cloud Run SA as much as possible. However, when I attempt to grant this SA run.viewer role only on the service it is assigned to, then we run into an issue where the very first deployment of a service fails, because Berglas is unable to read its own service's env vars (since we can't grant the role until we deploy the service). We then grant it this role on the service, and have to re-deploy the service once again to make it work.

Compare this e.g. to Cloud Functions, where env vars are automatically "passed" to the runtime, without having to grant any additional roles to read them (so a GCF SA could have literally 0 permissions if desired).

Thanks!

Saving decrypted secret to file doesn't work on Windows

When I try to test berglas on windows machine, it can't save a decrypted secret into file.

$ echo %VAR%
berglas://my-bucket/my-secret?destination=tempfile

$ cat echo-var.bat
@echo %VAR%

berglas exec --local -- echo-var.bat
failed to chmod filepath C:\Users\xakep\AppData\Local\Temp\berglas-901227331: chmod C:\Users\xakep\AppData\Local\Temp\berglas-901227331: not supported by windows

Maybe this error should be ignored on Windows letting the process to continue?

Or maybe it's not secure to leave default file attributes.. But I think berglas is not intended to be used on Windows in production, so ignore chmod error is better than just not work at all.

Question about newlines

Hi,

I run into an issue when using berglas locally with berglas exec --local. It seems a newline character is added to the decrypted environment variable, which isn't a part of the originally encrypted secret.

Here is a detailed walkthrough of my testing with this, and a reproduction path:

  • create secret:
$ echo 'testsecretwithoutnewline' | berglas create berglas-wietse/testsecret -  --key projects/berglas-wietse/locations/global/keyRings/berglas/cryptoKeys/berglas-key
Successfully created secret [testsecret] with generation [1569245517544173]
  • Validate it's there:
$ berglas access berglas-wietse/testsecret
testsecretwithoutnewline
  • Validate there is no newline
$ TESTENV=$(berglas access berglas-wietse/testsecret)
$ echo "ONE${TESTENV}TWO"
ONEtestsecretwithoutnewlineTWO
  • Use berglas exec
$ export TESTENV=berglas://berglas-wietse/testsecret
$ berglas exec --local ${SHELL}
$ echo "ONE${TESTENV}TWO"
ONEtestsecretwithoutnewline
TWO

As you can see, in the berglas exec environment, a newline at the end of the secret is suddenly added.

Binary permissions

After downloading the Linux binary I had to chmod +x so it would run.

Maybe it should be mentioned in the README.

how to use berglas with kubernetes daemonset?

I did setup my kubernetes cluster following https://github.com/GoogleCloudPlatform/berglas/tree/master/examples/kubernetes.
It seems working fine for usual pods.
But, berglas does not work well for daemonsets becasuse of either MutatingWebhookConfiguration or because sidecar does not start for daemonset.

Could you tell me how to use berglas with daemonset? I want to use datadog-agent https://docs.datadoghq.com/agent/kubernetes/daemonset_setup/?tab=k8sfile#create-manifest and want to use berglas for DD_API_KEY.

Add a subcommand to generate a completion script

Cobra has a builtin generator to create completion scripts for bash and zsh. Many projects make use of this generator, among others sigs.k8s.io/krew, k8s.io/minikube, or GoogleContainerTools/skaffold. This is usually used as source <(berglas completion zsh) in your shell, which then offers an improved CLI experience -- especially for new and casual users.

Is there a particular reason why berglas does not want that?

Go: berglas pkg/auto imports must panic on failure

I'm doing

import _ "github.com/GoogleCloudPlatform/berglas/pkg/auto"

in my Go app and it starts/boots just fine (on Kubernetes, or on Cloud Run), only later I find out it actually printed some log lines with errors about secrets initialization.

As a user I expect app to crash ASAP as there's no point of moving the app forward if a requirement cannot be initialized. It's certain that app will crash, and crashing early is a very conventional readiness/health check (recognized by runtimes like Kubernetes or Cloud Run).

image

[Proposal] New command: edit

Spec:

Update the contents of a secret by reading the encrypted data from Google
Cloud Storage, decrypting it with Google Cloud KMS, editing it in-place using an editor,
encrypting the updated content using Google Cloud KMS, writing it back into Google
Cloud Storage. The file MUST be saved and editor MUST exit with exit code 0 for the
secret to update.

Usage:
  berglas edit [secret] [flags]

Examples:
  # Edit a secret named "api-key" from the bucket "my-secrets"
  berglas edit my-secrets/api-key

Flags:
  --editor  the command to open a new editor. If this flag is not specified,
     it defaults to reading env vars `VISUAL`, or `EDITOR` (in that order).
     If neither environment variable is found, these commands are attempted:
     `vi`, `emacs`, `nano`, `pico`.
     The command is invoked with just one argument: a temporary filename
     with contents of the secret. The command MUST exit with code 0.
  -h, --help   help for edit

There is some assumption about file contents here (that they are editable using an editor and is not, say, a pdf file). However, by using the --editor flag you can specify, for example, Acrobat Pro for pdf, your choice of editor that can handle the file contents.

If this command exists, I would also recommend changing create so it doesn't silently overwrite, but fails with error, and you have to use the edit command to update secrets.

help with cloudrun and wordpress

can anyone give a non programmer like me instructions on how to use Berglas to startup wordpress

i'm looking at these directions:

First, we set the credentials to access to the database through environment variables (we use PHP function getenv):

define( 'DB_NAME', getenv('DB_NAME')  );
/** MySQL database username */
define( 'DB_USER', getenv('DB_USER') );
/** MySQL database password */
define( 'DB_PASSWORD', getenv('DB_PASSWORD') );
/** MySQL hostname */
define( 'DB_HOST', getenv('DB_HOST') );

It would be correct to pass this sensitive data through secrets but they are not (currently) natively supported by Cloud Run: for the sake of simplicity we will just pass them as plain-text but for production deploy it is absolutely recommended to use one of the possible workarounds available here https://www.sethvargo.com/secrets-in-serverless/.

document required scopes and where to set them

Thanks very much for Berglas. I was very excited to find a native Go option for secret management.

I'm having a hard time figuring out how to set sufficient scopes for my service account to read secrets. I'm using berglas.Replace. The error I'm getting (mildly redacted) is:

failed to access secret BUCKET/SECRET: failed to access secret: failed to decrypt dek: rpc error: code = PermissionDenied desc = Request had insufficient authentication scopes.

I don't see anything documented about what permissions the service account needs (or for that matter, how to provide them). I gave it IAM roles Storage Object Viewer and Cloud KMS CryptoKey Decrypter.

Apologies for what is definitely a naive and possibly also a stupid question. Thanks.

Enabling KMS API not listed as an instruction

berglas bootstrap --project $PROJECT_ID --bucket $BUCKET_ID

failed to create KMS key ring berglas: rpc error: code = FailedPrecondition desc = Google Cloud KMS API has not been used in this project before, or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudkms.googleapis.com/overview?project=1075231961184 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.

Using berglas on Container-Optimized OS

Hi,

I've been trying to use berglas on a Container-Optimized OS but it fails to detect the runtime, is that by design or is this unexpected?

While examining my docker logs for the container, I see the following error message:

failed to detect runtime environment: unknown runtime

It's related to this code which made me wonder if it's design or not.

Or should --local flag be used for Container-Optimized OS as it looks like I could not spot a reliable way to identify the runtime for it other than talking to the metadata service.

Thanks!

Support for versioning

This is a great tool, and we're evaluating using it as a config manager (a la Heroku). The one feature that's missing is the ability to rollback easily by providing versioning. We can easily piggyback on GCS's versioning scheme that generates a new generation every time you change an object in a bucket that has versioning enabled. The access command could provide an additional flag which would return previous version of the object. The exec command could do that as well, or just use latest version - which is fine in most cases.

enhancement: capability to add label to the secret bucket

This bucket will be used to store the secret and the project can have multiple buckets.
There should be a capability to add labels like owner:name, classification: confidential to easily distinguished between the buckets to get a report.

RFE: Kubernetes secret volume support

It looks like the current implementation handles berglas env variable references.

It would be nice to be able to mount K8S secret volumes that reference berglas secrets. Not 100% sure how it work - but perhaps if the opaque secret starts with berglass:// it indicates that the actual value should be pulled from berglas?

Clarification regarding release security

The README states that "Berglas is not an officially supported Google product" but could it be clarified whether Berglas is still subject to Google's usual internal security measures (e.g. secure builds, code security, reviews, etc)?

Thanks!

Kubernetes: support for envFrom?

It would be awesome to have support for deployments with:

envFrom:
    - secretRef:
        name: berglas://bucket/foo

where bucket/foo is a file such as:

FOO=QkFSCg==

which is specially useful for deployments with hundreds of secret envs. Defining one env: per secret would be cumbersome.

Support for GAE

This seems like it should work just like Cloud Run, except it just hasn't been done yet - is that correct? If so, I can take this on..

ca-certificates with node:10-alpine

Problem

I followed the node.js & Cloud Run example you have here and the resultant image was 300+MBs. Switching to node:10-alpine I than ran into this issue on deployment

failed to find environment variables: failed to execute cloud run request: Get https://us-central1-run.googleapis.com/apis/serving.knative.dev/v1alpha1/namespaces/project-id/revisions/service-name-00015: x509: certificate signed by unknown authority

Here is the Dockerfile

FROM node:10-alpine

ENV NODE_ENV=production
WORKDIR /urs/src/app

COPY package.json yarn.lock ./
RUN yarn install --production

COPY . ./
COPY --from=gcr.io/berglas/berglas:latest /bin/berglas /bin/berglas

ENTRYPOINT exec /bin/berglas exec -- yarn start

Expectations

I expected this to work without me needing to add ca-certificates as a package to the Docker image as it is contained within the Berglas image.

Temporary Solution

adding RUN apk add ca-certificates to my Dockerfile solved the issue and I get an image around 30MBs in size 🎉

Full example code here: https://github.com/jthegedus/firebase-gcp-examples/tree/master/gcp-cloudrun-berglas/helloService

Question

Are my assumptions incorrect here, or is this a bug with Berglas?

Regardless of using tags or not, download is always of v0.1.0

Hi there,

Just a heads-up that trying to follow the download instructions that reads:

This will download the latest version built against the master branch. To download a specific version, specify a git tag in place of "master" in the URL.

Always gives me the 0.1.0 version.

Tried:

# tag 0.1.2
$ curl -O https://storage.googleapis.com/berglas/0.1.2/darwin_amd64/berglas
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 12.7M  100 12.7M    0     0  4467k      0  0:00:02  0:00:02 --:--:-- 4468k

$ chmod +x berglas
$ ./berglas version
0.1.0

# master
$ curl -O https://storage.googleapis.com/berglas/master/darwin_amd64/berglas
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 12.7M  100 12.7M    0     0  5368k      0  0:00:02  0:00:02 --:--:-- 5368k

$ chmod +x berglas
$ ./berglas version
0.1.0

Hope I'm not missing something and just creating noise.
Best regards,
Rafa

Running locally

hello! thanks for this library. I'm trying to speed up my development cycles and obviously its slow to rebuild/re-deploy to make sure everything works.

i was hoping to run locally before deploying to Cloud Run. However i get this error when i try

  1. running locally with golang
  2. running locally with docker + env variables
2019/08/30 20:48:52 failed to detect environment: unknown runtime
panic: failed to detect environment: unknown runtime

goroutine 1 [running]:
github.com/GoogleCloudPlatform/berglas/pkg/auto.handleError(...)
	/src/vendor/github.com/GoogleCloudPlatform/berglas/pkg/auto/importer.go:108
github.com/GoogleCloudPlatform/berglas/pkg/auto.init.0()
	/src/vendor/github.com/GoogleCloudPlatform/berglas/pkg/auto/importer.go:44 +0x64e

its the same error whether i run using a container or locally and it's the auto package. If i comment that import out everything works locally (sort of).

there isn't any documentation about local run vs deployed run. would be awesome to have that. for now i'm going to just do the wrong thing with env vars in a cloud function...

i am running on macOS with docker for Mac and go 1.12 otherwise.
thanks again!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.