Skip to content

Commit

Permalink
Introduce the gcp_cloudstorage BundlePublisher plugin (spiffe#4961)
Browse files Browse the repository at this point in the history
* Introduce the `gcp_cloudstorage` BundlePublisher plugin

Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>

* Address PR comments

Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>

---------

Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
Co-authored-by: Marcos Yacob <marcos.yacob@hpe.com>
  • Loading branch information
2 people authored and rushi47 committed Apr 11, 2024
1 parent ce36552 commit 879b51d
Show file tree
Hide file tree
Showing 6 changed files with 790 additions and 27 deletions.
69 changes: 69 additions & 0 deletions doc/plugin_server_bundlepublisher_gcp_cloudstorage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Server plugin: BundlePublisher "gcp_cloudstorage"

The `gcp_cloudstorage` plugin puts the current trust bundle of the server in a designated
Google Cloud Storage bucket, keeping it updated.

The plugin accepts the following configuration options:

| Configuration | Description | Required | Default |
|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|----------------------------------------------------------------|
| service_account_file | Path to the service account file used to authenticate with the Cloud Storage API. | No. | Value of `GOOGLE_APPLICATION_CREDENTIALS` environment variable.|
| bucket_name | The Google Cloud Storage bucket name to which the trust bundle is uploaded. | Yes. | |
| object_name | The object name inside the bucket. | Yes. | |
| format | Format in which the trust bundle is stored, &lt;spiffe &vert; jwks &vert; pem&gt;. See [Supported bundle formats](#supported-bundle-formats) for more details. | Yes. | |

## Supported bundle formats

The following bundle formats are supported:

### SPIFFE format

The trust bundle is represented as an RFC 7517 compliant JWK Set, with the specific parameters defined in the [SPIFFE Trust Domain and Bundle specification](https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Trust_Domain_and_Bundle.md#4-spiffe-bundle-format). Both the JWT authorities and the X.509 authorities are included.

### JWKS format

The trust bundle is encoded as an RFC 7517 compliant JWK Set, omitting SPIFFE-specific parameters. Both the JWT authorities and the X.509 authorities are included.

### PEM format

The trust bundle is formatted using PEM encoding. Only the X.509 authorities are included.

## Required permissions

The plugin requires the following IAM permissions be granted to the authenticated service account in the configured bucket:

```text
storage.objects.create
storage.objects.delete
```

The `storage.objects.delete` permission is required to overwrite the object when the bundle is updated.

## Sample configuration using Application Default Credentials

The following configuration uploads the local trust bundle contents to the `example.org` object in the `spire-bundle` bucket. Since `service_account_file` is not configured, [Application Default Credentials](https://cloud.google.com/docs/authentication/client-libraries#adc) are used.

```hcl
BundlePublisher "gcp_cloudstorage" {
plugin_data {
bucket = "spire-bundle"
object_name = "example.org"
format = "spiffe"
}
}
```

## Sample configuration using service account file

The following configuration uploads the local trust bundle contents to the `example.org` object in the `spire-bundle` bucket. Since `service_account_file` is configured, authentication to the Cloud Storage API is done with the given service account file.

```hcl
BundlePublisher "gcp_cloudstorage" {
plugin_data {
service_account_file = "/path/to/service/account/file"
bucket = "spire-bundle"
object_name = "example.org"
format = "spiffe"
}
}
```
55 changes: 28 additions & 27 deletions doc/spire_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,37 @@ This document is a configuration reference for SPIRE Server. It includes informa
| NodeAttestor | Implements validation logic for nodes attempting to assert their identity. Generally paired with an agent plugin of the same type. |
| UpstreamAuthority | Allows SPIRE server to integrate with existing PKI systems. |
| Notifier | Notified by SPIRE server for certain events that are happening or have happened. For events that are happening, the notifier can advise SPIRE server on the outcome. |
| BundlePublisher | Publishes trust bundles to additional locations. |
| BundlePublisher | Publishes the local trust bundle to a store. |

## Built-in plugins

| Type | Name | Description |
|--------------------|----------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| DataStore | [sql](/doc/plugin_server_datastore_sql.md) | An SQL database storage for SQLite, PostgreSQL and MySQL databases for the SPIRE datastore |
| KeyManager | [aws_kms](/doc/plugin_server_keymanager_aws_kms.md) | A key manager which manages keys in AWS KMS |
| KeyManager | [disk](/doc/plugin_server_keymanager_disk.md) | A key manager which manages keys persisted on disk |
| KeyManager | [memory](/doc/plugin_server_keymanager_memory.md) | A key manager which manages unpersisted keys in memory |
| CredentialComposer | [uniqueid](/doc/plugin_server_credentialcomposer_uniqueid.md) | Adds the x509UniqueIdentifier attribute to workload X509-SVIDs. |
| NodeAttestor | [aws_iid](/doc/plugin_server_nodeattestor_aws_iid.md) | A node attestor which attests agent identity using an AWS Instance Identity Document |
| NodeAttestor | [azure_msi](/doc/plugin_server_nodeattestor_azure_msi.md) | A node attestor which attests agent identity using an Azure MSI token |
| NodeAttestor | [gcp_iit](/doc/plugin_server_nodeattestor_gcp_iit.md) | A node attestor which attests agent identity using a GCP Instance Identity Token |
| NodeAttestor | [join_token](/doc/plugin_server_nodeattestor_jointoken.md) | A node attestor which validates agents attesting with server-generated join tokens |
| NodeAttestor | [k8s_sat](/doc/plugin_server_nodeattestor_k8s_sat.md) (deprecated) | A node attestor which attests agent identity using a Kubernetes Service Account token |
| NodeAttestor | [k8s_psat](/doc/plugin_server_nodeattestor_k8s_psat.md) | A node attestor which attests agent identity using a Kubernetes Projected Service Account token |
| NodeAttestor | [sshpop](/doc/plugin_server_nodeattestor_sshpop.md) | A node attestor which attests agent identity using an existing ssh certificate |
| NodeAttestor | [tpm_devid](/doc/plugin_server_nodeattestor_tpm_devid.md) | A node attestor which attests agent identity using a TPM that has been provisioned with a DevID certificate |
| NodeAttestor | [x509pop](/doc/plugin_server_nodeattestor_x509pop.md) | A node attestor which attests agent identity using an existing X.509 certificate |
| UpstreamAuthority | [disk](/doc/plugin_server_upstreamauthority_disk.md) | Uses a CA loaded from disk to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [aws_pca](/doc/plugin_server_upstreamauthority_aws_pca.md) | Uses a Private Certificate Authority from AWS Certificate Manager to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [awssecret](/doc/plugin_server_upstreamauthority_awssecret.md) | Uses a CA loaded from AWS SecretsManager to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [gcp_cas](/doc/plugin_server_upstreamauthority_gcp_cas.md) | Uses a Private Certificate Authority from GCP Certificate Authority Service to sign SPIRE Server intermediate certificates. |
| UpstreamAuthority | [vault](/doc/plugin_server_upstreamauthority_vault.md) | Uses a PKI Secret Engine from HashiCorp Vault to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [spire](/doc/plugin_server_upstreamauthority_spire.md) | Uses an upstream SPIRE server in the same trust domain to obtain intermediate signing certificates for SPIRE server. |
| UpstreamAuthority | [cert-manager](/doc/plugin_server_upstreamauthority_cert_manager.md) | Uses a referenced cert-manager Issuer to request intermediate signing certificates. |
| Notifier | [gcs_bundle](/doc/plugin_server_notifier_gcs_bundle.md) | A notifier that pushes the latest trust bundle contents into an object in Google Cloud Storage. |
| Notifier | [k8sbundle](/doc/plugin_server_notifier_k8sbundle.md) | A notifier that pushes the latest trust bundle contents into a Kubernetes ConfigMap. |
| BundlePublisher | [aws_s3](/doc/plugin_server_bundlepublisher_aws_s3.md) | Publishes trust bundles to an Amazon S3 bucket. |
| Type | Name | Description |
|--------------------|----------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| DataStore | [sql](/doc/plugin_server_datastore_sql.md) | An SQL database storage for SQLite, PostgreSQL and MySQL databases for the SPIRE datastore |
| KeyManager | [aws_kms](/doc/plugin_server_keymanager_aws_kms.md) | A key manager which manages keys in AWS KMS |
| KeyManager | [disk](/doc/plugin_server_keymanager_disk.md) | A key manager which manages keys persisted on disk |
| KeyManager | [memory](/doc/plugin_server_keymanager_memory.md) | A key manager which manages unpersisted keys in memory |
| CredentialComposer | [uniqueid](/doc/plugin_server_credentialcomposer_uniqueid.md) | Adds the x509UniqueIdentifier attribute to workload X509-SVIDs. |
| NodeAttestor | [aws_iid](/doc/plugin_server_nodeattestor_aws_iid.md) | A node attestor which attests agent identity using an AWS Instance Identity Document |
| NodeAttestor | [azure_msi](/doc/plugin_server_nodeattestor_azure_msi.md) | A node attestor which attests agent identity using an Azure MSI token |
| NodeAttestor | [gcp_iit](/doc/plugin_server_nodeattestor_gcp_iit.md) | A node attestor which attests agent identity using a GCP Instance Identity Token |
| NodeAttestor | [join_token](/doc/plugin_server_nodeattestor_jointoken.md) | A node attestor which validates agents attesting with server-generated join tokens |
| NodeAttestor | [k8s_sat](/doc/plugin_server_nodeattestor_k8s_sat.md) (deprecated) | A node attestor which attests agent identity using a Kubernetes Service Account token |
| NodeAttestor | [k8s_psat](/doc/plugin_server_nodeattestor_k8s_psat.md) | A node attestor which attests agent identity using a Kubernetes Projected Service Account token |
| NodeAttestor | [sshpop](/doc/plugin_server_nodeattestor_sshpop.md) | A node attestor which attests agent identity using an existing ssh certificate |
| NodeAttestor | [tpm_devid](/doc/plugin_server_nodeattestor_tpm_devid.md) | A node attestor which attests agent identity using a TPM that has been provisioned with a DevID certificate |
| NodeAttestor | [x509pop](/doc/plugin_server_nodeattestor_x509pop.md) | A node attestor which attests agent identity using an existing X.509 certificate |
| UpstreamAuthority | [disk](/doc/plugin_server_upstreamauthority_disk.md) | Uses a CA loaded from disk to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [aws_pca](/doc/plugin_server_upstreamauthority_aws_pca.md) | Uses a Private Certificate Authority from AWS Certificate Manager to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [awssecret](/doc/plugin_server_upstreamauthority_awssecret.md) | Uses a CA loaded from AWS SecretsManager to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [gcp_cas](/doc/plugin_server_upstreamauthority_gcp_cas.md) | Uses a Private Certificate Authority from GCP Certificate Authority Service to sign SPIRE Server intermediate certificates. |
| UpstreamAuthority | [vault](/doc/plugin_server_upstreamauthority_vault.md) | Uses a PKI Secret Engine from HashiCorp Vault to sign SPIRE server intermediate certificates. |
| UpstreamAuthority | [spire](/doc/plugin_server_upstreamauthority_spire.md) | Uses an upstream SPIRE server in the same trust domain to obtain intermediate signing certificates for SPIRE server. |
| UpstreamAuthority | [cert-manager](/doc/plugin_server_upstreamauthority_cert_manager.md) | Uses a referenced cert-manager Issuer to request intermediate signing certificates. |
| Notifier | [gcs_bundle](/doc/plugin_server_notifier_gcs_bundle.md) | A notifier that pushes the latest trust bundle contents into an object in Google Cloud Storage. |
| Notifier | [k8sbundle](/doc/plugin_server_notifier_k8sbundle.md) | A notifier that pushes the latest trust bundle contents into a Kubernetes ConfigMap. |
| BundlePublisher | [aws_s3](/doc/plugin_server_bundlepublisher_aws_s3.md) | Publishes the trust bundle to an Amazon S3 bucket. |
| BundlePublisher | [gcp_cloudstorage](/doc/plugin_server_bundlepublisher_gcp_cloudstorage.md) | Publishes the trust bundle to a Google Cloud Storage bucket. |

## Server configuration file

Expand Down
2 changes: 2 additions & 0 deletions pkg/server/catalog/bundlepublisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/spiffe/spire/pkg/common/catalog"
"github.com/spiffe/spire/pkg/server/plugin/bundlepublisher"
"github.com/spiffe/spire/pkg/server/plugin/bundlepublisher/awss3"
"github.com/spiffe/spire/pkg/server/plugin/bundlepublisher/gcpcloudstorage"
)

type bundlePublisherRepository struct {
Expand All @@ -25,6 +26,7 @@ func (repo *bundlePublisherRepository) Versions() []catalog.Version {
func (repo *bundlePublisherRepository) BuiltIns() []catalog.BuiltIn {
return []catalog.BuiltIn{
awss3.BuiltIn(),
gcpcloudstorage.BuiltIn(),
}
}

Expand Down
22 changes: 22 additions & 0 deletions pkg/server/plugin/bundlepublisher/gcpcloudstorage/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gcpcloudstorage

import (
"context"
"io"

"cloud.google.com/go/storage"
"google.golang.org/api/option"
)

type gcsService interface {
Bucket(name string) *storage.BucketHandle
Close() error
}

func newGCSClient(ctx context.Context, opts ...option.ClientOption) (gcsService, error) {
return storage.NewClient(ctx, opts...)
}

func newStorageWriter(ctx context.Context, o *storage.ObjectHandle) io.WriteCloser {
return o.NewWriter(ctx)
}
Loading

0 comments on commit 879b51d

Please sign in to comment.