This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch gcp-vault-1.10.x in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 416f2afe5e49c2d3a89659d1cb52ff369f28fadd Author: Andrea Cosentino <anco...@gmail.com> AuthorDate: Thu Sep 29 11:38:25 2022 +0200 Added Support GCP Secret Manager Vault from Camel --- addons/register_gcp_secrets.go | 27 +++++++++ addons/vault/gcp/gcp_secret_manager.go | 94 +++++++++++++++++++++++++++++ addons/vault/gcp/gcp_secret_manager_test.go | 94 +++++++++++++++++++++++++++++ pkg/apis/camel/v1/common_types.go | 2 + pkg/resources/resources.go | 4 +- 5 files changed, 219 insertions(+), 2 deletions(-) diff --git a/addons/register_gcp_secrets.go b/addons/register_gcp_secrets.go new file mode 100644 index 000000000..f82d0aacd --- /dev/null +++ b/addons/register_gcp_secrets.go @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package addons + +import ( + "github.com/apache/camel-k/addons/vault/gcp" + "github.com/apache/camel-k/pkg/trait" +) + +func init() { + trait.AddToTraits(gcp.NewGcpSecretManagerTrait) +} diff --git a/addons/vault/gcp/gcp_secret_manager.go b/addons/vault/gcp/gcp_secret_manager.go new file mode 100644 index 000000000..552e716bc --- /dev/null +++ b/addons/vault/gcp/gcp_secret_manager.go @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gcp + +import ( + "strconv" + + v1 "github.com/apache/camel-k/pkg/apis/camel/v1" + traitv1 "github.com/apache/camel-k/pkg/apis/camel/v1/trait" + "github.com/apache/camel-k/pkg/trait" + "github.com/apache/camel-k/pkg/util" + "k8s.io/utils/pointer" +) + +// The Google Secret Manager trait can be used to use secrets from Google Secret Manager +// +// The Google Secret Manager trait is disabled by default. +// +// For more information about how to use secrets from Google Secret Manager take a look at the components docs: xref:components::google-secret-manager-component.adoc[AWS Secrets Manager component] +// +// A sample execution of this trait, would require +// the following trait options: +// -t aws-secrets-manager.enabled=true -t aws-secrets-manager.access-key="aws-access-key" -t aws-secrets-manager.secret-key="aws-secret-key" -t aws-secrets-manager.region="aws-region" +// +// +camel-k:trait=gcp-secret-manager. +type Trait struct { + traitv1.Trait `property:",squash"` + // Enables automatic configuration of the trait. + Auto *bool `property:"auto" json:"auto,omitempty"` + // The Project Id from Google Cloud + ProjectId string `property:"project-id,omitempty"` + // The Path to a service account Key File to use secrets from Google Secret Manager + ServiceAccountKey string `property:"service-account-key,omitempty"` + // Define if we want to use the Default Instance approach for accessing the Google Secret Manager service + UseDefaultInstance *bool `property:"use-default-instance,omitempty"` +} + +type gcpSecretManagerTrait struct { + trait.BaseTrait + Trait `property:",squash"` +} + +func NewGcpSecretManagerTrait() trait.Trait { + return &gcpSecretManagerTrait{ + BaseTrait: trait.NewBaseTrait("gcp-secret-manager", trait.TraitOrderBeforeControllerCreation), + } +} + +func (t *gcpSecretManagerTrait) Configure(environment *trait.Environment) (bool, error) { + if !pointer.BoolDeref(t.Enabled, false) { + return false, nil + } + + if !environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !environment.IntegrationInRunningPhases() { + return false, nil + } + + if t.UseDefaultInstance == nil { + t.UseDefaultInstance = pointer.Bool(false) + } + + return true, nil +} + +func (t *gcpSecretManagerTrait) Apply(environment *trait.Environment) error { + if environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) { + util.StringSliceUniqueAdd(&environment.Integration.Status.Capabilities, v1.CapabilityGcpSecretManager) + // Add the Camel Quarkus Google Secrets Manager dependency + util.StringSliceUniqueAdd(&environment.Integration.Status.Dependencies, "mvn:org.apache.camel.quarkus:camel-quarkus-google-secret-manager") + } + + if environment.IntegrationInRunningPhases() { + environment.ApplicationProperties["camel.vault.gcp.projectId"] = t.ProjectId + environment.ApplicationProperties["camel.vault.gcp.serviceAccountKey"] = t.ServiceAccountKey + environment.ApplicationProperties["camel.vault.gcp.useDefaultInstance"] = strconv.FormatBool(*t.UseDefaultInstance) + } + + return nil +} diff --git a/addons/vault/gcp/gcp_secret_manager_test.go b/addons/vault/gcp/gcp_secret_manager_test.go new file mode 100644 index 000000000..3407ed751 --- /dev/null +++ b/addons/vault/gcp/gcp_secret_manager_test.go @@ -0,0 +1,94 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gcp + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + + v1 "github.com/apache/camel-k/pkg/apis/camel/v1" + "github.com/apache/camel-k/pkg/trait" + "github.com/apache/camel-k/pkg/util/camel" + + "github.com/stretchr/testify/assert" +) + +func TestGcpSecretManagerTraitApply(t *testing.T) { + e := createEnvironment(t, camel.QuarkusCatalog) + gcp := NewGcpSecretManagerTrait() + secrets, _ := gcp.(*gcpSecretManagerTrait) + secrets.Enabled = pointer.Bool(true) + secrets.UseDefaultInstance = pointer.Bool(false) + secrets.ProjectId = "project-gcp" + secrets.ServiceAccountKey = "file:////usr/local/serviceaccount.json" + ok, err := secrets.Configure(e) + assert.Nil(t, err) + assert.True(t, ok) + + err = secrets.Apply(e) + assert.Nil(t, err) + + assert.Equal(t, "project-gcp", e.ApplicationProperties["camel.vault.gcp.projectId"]) + assert.Equal(t, "file:////usr/local/serviceaccount.json", e.ApplicationProperties["camel.vault.gcp.serviceAccountKey"]) + assert.Equal(t, "false", e.ApplicationProperties["camel.vault.gcp.useDefaultInstance"]) +} + +func TestGcpSecretManagerTraitNoDefaultCreds(t *testing.T) { + e := createEnvironment(t, camel.QuarkusCatalog) + gcp := NewGcpSecretManagerTrait() + secrets, _ := gcp.(*gcpSecretManagerTrait) + secrets.Enabled = pointer.Bool(true) + secrets.UseDefaultInstance = pointer.Bool(false) + secrets.ProjectId = "project-gcp" + secrets.ServiceAccountKey = "file:////usr/local/serviceaccount.json" + ok, err := secrets.Configure(e) + assert.Nil(t, err) + assert.True(t, ok) + + err = secrets.Apply(e) + assert.Nil(t, err) + + assert.Equal(t, "project-gcp", e.ApplicationProperties["camel.vault.gcp.projectId"]) + assert.Equal(t, "file:////usr/local/serviceaccount.json", e.ApplicationProperties["camel.vault.gcp.serviceAccountKey"]) + assert.Equal(t, "false", e.ApplicationProperties["camel.vault.gcp.useDefaultInstance"]) +} + +func createEnvironment(t *testing.T, catalogGen func() (*camel.RuntimeCatalog, error)) *trait.Environment { + t.Helper() + + catalog, err := catalogGen() + assert.Nil(t, err) + + e := trait.Environment{ + CamelCatalog: catalog, + ApplicationProperties: make(map[string]string), + } + + it := v1.Integration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Status: v1.IntegrationStatus{ + Phase: v1.IntegrationPhaseDeploying, + }, + } + e.Integration = &it + return &e +} diff --git a/pkg/apis/camel/v1/common_types.go b/pkg/apis/camel/v1/common_types.go index 2e7e485a4..6b141a221 100644 --- a/pkg/apis/camel/v1/common_types.go +++ b/pkg/apis/camel/v1/common_types.go @@ -308,6 +308,8 @@ const ( CapabilityResumeKafka = "resume-kafka" // CapabilityAwsSecretsManager defines the aws secrets manager capability CapabilityAwsSecretsManager = "aws-secrets-manager" + // CapabilityGcpSecretManager defines the gcp secret manager capability + CapabilityGcpSecretManager = "gcp-secret-manager" ) // +kubebuilder:object:generate=false diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go index fd82a9cb0..cec9cabf0 100644 --- a/pkg/resources/resources.go +++ b/pkg/resources/resources.go @@ -611,9 +611,9 @@ var assets = func() http.FileSystem { "/traits.yaml": &vfsgen۰CompressedFileInfo{ name: "traits.yaml", modTime: time.Time{}, - uncompressedSize: 53036, + uncompressedSize: 56535, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x7b\x73\x1b\xb9\xb5\x20\xfe\xff\x7c\x0a\x94\xee\xef\x96\x25\x17\x49\x79\x26\x77\x72\xe7\xa7\xdd\xb9\x59\x8d\xed\x49\x34\xe3\x87\xd6\xf2\x4c\x6e\xca\xeb\x0a\xc1\x6e\x90\x84\xd9\x04\x3a\x00\x5a\x32\xb3\xd9\xef\xbe\x85\xf3\x00\xd0\x64\x4b\xa2\x6c\x6b\x36\xda\xda\x4c\x55\x2c\x92\xdd\xc0\xc1\xc1\x39\x07\xe7\x8d\xe0\xa4\x0e\xfe\xe4\xab\xb1\x30\x72\xad\x4e\xc4\xef\x7c\x25\x1b\xf5\x95\x10\x6d\x23\xc3\xdc\xba\xf5\x89\x [...] + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\xfd\x73\x1b\x37\xb2\xe0\xef\xf9\x2b\x50\x7a\xf7\x4a\x92\x8b\xa4\x94\xec\xcb\xbe\x3c\xdd\xf9\xed\x29\xb6\xb3\xab\xc4\x1f\x3a\x4b\xc9\xbe\x2d\x9f\x6b\x09\xce\x80\x24\xcc\x19\x60\x02\x60\x24\x33\xf7\xee\x7f\xbf\x42\x77\xe3\x63\x86\x43\x91\xb2\xad\xdc\xea\xea\x36\x55\x6b\x91\x9c\x01\x1a\x8d\x46\xa3\xbf\xdb\x19\x2e\x9d\x3d\xfb\x6a\xcc\x14\xaf\xc5\x19\xfb\x83\x2d\x78\x25\xbe\x62\xac\xa9\xb8\x9b\x6b\x53\x9f\xb1\x39\x [...] }, } fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{