You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2023/10/05 13:24:17 UTC

[camel-k] branch 4743-hashicorp-vault created (now 15083c455)

This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a change to branch 4743-hashicorp-vault
in repository https://gitbox.apache.org/repos/asf/camel-k.git


      at 15083c455 Kamelet - Inject secret in Vaults - Hashicorp Vault

This branch includes the following new commits:

     new 15083c455 Kamelet - Inject secret in Vaults - Hashicorp Vault

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[camel-k] 01/01: Kamelet - Inject secret in Vaults - Hashicorp Vault

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch 4743-hashicorp-vault
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 15083c45564efbbda85637a263de240bb6f0b69a
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Thu Oct 5 15:23:09 2023 +0200

    Kamelet - Inject secret in Vaults - Hashicorp Vault
    
    Signed-off-by: Andrea Cosentino <an...@gmail.com>
---
 addons/vault/hashicorp/hashicorp_vault.go          | 20 +++++-
 addons/vault/hashicorp/hashicorp_vault_test.go     | 84 +++++++++++++++++++++-
 docs/modules/traits/pages/aws-secrets-manager.adoc |  4 +-
 docs/modules/traits/pages/hashicorp-vault.adoc     |  4 +-
 resources/traits.yaml                              | 16 +++--
 5 files changed, 115 insertions(+), 13 deletions(-)

diff --git a/addons/vault/hashicorp/hashicorp_vault.go b/addons/vault/hashicorp/hashicorp_vault.go
index e3eefed8e..058b18cc9 100644
--- a/addons/vault/hashicorp/hashicorp_vault.go
+++ b/addons/vault/hashicorp/hashicorp_vault.go
@@ -18,10 +18,13 @@ limitations under the License.
 package hashicorp
 
 import (
+	"regexp"
+
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 	traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
 	"github.com/apache/camel-k/v2/pkg/trait"
 	"github.com/apache/camel-k/v2/pkg/util"
+	"github.com/apache/camel-k/v2/pkg/util/kubernetes"
 	"k8s.io/utils/pointer"
 )
 
@@ -46,7 +49,9 @@ type Trait struct {
 	Port string `property:"port" json:"port,omitempty"`
 	// The Hashicorp engine to use
 	Engine string `property:"engine" json:"engine,omitempty"`
-	// The token to access Hashicorp Vault
+	// The token to access Hashicorp Vault. This could be a plain text or a configmap/secret
+	// The content of the hashicorp vault token is expected to be a text containing a valid Hashicorp Vault Token.
+	// Syntax: [configmap|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = hashicorp-vault-token).
 	Token string `property:"token" json:"token,omitempty"`
 	// The scheme to access Hashicorp Vault
 	Scheme string `property:"scheme" json:"scheme,omitempty"`
@@ -76,6 +81,7 @@ func (t *hashicorpVaultTrait) Configure(environment *trait.Environment) (bool, e
 }
 
 func (t *hashicorpVaultTrait) Apply(environment *trait.Environment) error {
+	rex := regexp.MustCompile(`^(configmap|secret):([a-zA-Z0-9][a-zA-Z0-9-]*)(/([a-zA-Z0-9].*))?$`)
 	if environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
 		util.StringSliceUniqueAdd(&environment.Integration.Status.Capabilities, v1.CapabilityHashicorpVault)
 		// Deprecated
@@ -84,7 +90,17 @@ func (t *hashicorpVaultTrait) Apply(environment *trait.Environment) error {
 	}
 
 	if environment.IntegrationInRunningPhases() {
-		environment.ApplicationProperties["camel.vault.hashicorp.token"] = t.Token
+		hits := rex.FindAllStringSubmatch(t.Token, -1)
+		if len(hits) >= 1 {
+			var res, _ = v1.DecodeValueSource(t.Token, "hashicorp-vault-token", "The Hashicorp Vault Token provided is not valid")
+			if secretValue, err := kubernetes.ResolveValueSource(environment.Ctx, environment.Client, environment.Platform.Namespace, &res); err != nil {
+				return err
+			} else if secretValue != "" {
+				environment.ApplicationProperties["camel.vault.hashicorp.token"] = string([]byte(secretValue))
+			}
+		} else {
+			environment.ApplicationProperties["camel.vault.hashicorp.token"] = t.Token
+		}
 		environment.ApplicationProperties["camel.vault.hashicorp.host"] = t.Host
 		environment.ApplicationProperties["camel.vault.hashicorp.port"] = t.Port
 		environment.ApplicationProperties["camel.vault.hashicorp.engine"] = t.Engine
diff --git a/addons/vault/hashicorp/hashicorp_vault_test.go b/addons/vault/hashicorp/hashicorp_vault_test.go
index 7333dffe1..86cb70229 100644
--- a/addons/vault/hashicorp/hashicorp_vault_test.go
+++ b/addons/vault/hashicorp/hashicorp_vault_test.go
@@ -20,6 +20,9 @@ package hashicorp
 import (
 	"testing"
 
+	"github.com/apache/camel-k/v2/pkg/util/test"
+	corev1 "k8s.io/api/core/v1"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
 
@@ -28,6 +31,7 @@ import (
 	"github.com/apache/camel-k/v2/pkg/util/camel"
 
 	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/runtime"
 )
 
 func TestHashicorpVaultTraitApply(t *testing.T) {
@@ -55,25 +59,101 @@ func TestHashicorpVaultTraitApply(t *testing.T) {
 	assert.Equal(t, "http", e.ApplicationProperties["camel.vault.hashicorp.scheme"])
 }
 
-func createEnvironment(t *testing.T, catalogGen func() (*camel.RuntimeCatalog, error)) *trait.Environment {
+func TestHashicorpVaultTraitWithSecretApply(t *testing.T) {
+	e := createEnvironment(t, camel.QuarkusCatalog, &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: "test",
+			Name:      "my-secret1",
+		},
+		Data: map[string][]byte{
+			"hashicorp-vault-token": []byte("my-hashicorp-vault-token"),
+		},
+	})
+	hashicorp := NewHashicorpVaultTrait()
+	secrets, _ := hashicorp.(*hashicorpVaultTrait)
+	secrets.Enabled = pointer.Bool(true)
+	secrets.Engine = "test"
+	secrets.Token = "secret:my-secret1/hashicorp-vault-token"
+	secrets.Host = "localhost"
+	secrets.Port = "9091"
+	secrets.Scheme = "http"
+	ok, err := secrets.Configure(e)
+	assert.Nil(t, err)
+	assert.True(t, ok)
+
+	err = secrets.Apply(e)
+	assert.Nil(t, err)
+
+	assert.Empty(t, e.ApplicationProperties["quarkus.jaeger.enabled"])
+	assert.Equal(t, "test", e.ApplicationProperties["camel.vault.hashicorp.engine"])
+	assert.Equal(t, "my-hashicorp-vault-token", e.ApplicationProperties["camel.vault.hashicorp.token"])
+	assert.Equal(t, "localhost", e.ApplicationProperties["camel.vault.hashicorp.host"])
+	assert.Equal(t, "9091", e.ApplicationProperties["camel.vault.hashicorp.port"])
+	assert.Equal(t, "http", e.ApplicationProperties["camel.vault.hashicorp.scheme"])
+}
+
+func TestHashicorpVaultTraitWithConfigMapApply(t *testing.T) {
+	e := createEnvironment(t, camel.QuarkusCatalog, &corev1.ConfigMap{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: "test",
+			Name:      "my-configmap1",
+		},
+		Data: map[string]string{
+			"hashicorp-vault-token": "my-hashicorp-vault-token",
+		},
+	})
+	hashicorp := NewHashicorpVaultTrait()
+	secrets, _ := hashicorp.(*hashicorpVaultTrait)
+	secrets.Enabled = pointer.Bool(true)
+	secrets.Engine = "test"
+	secrets.Token = "configmap:my-configmap1/hashicorp-vault-token"
+	secrets.Host = "localhost"
+	secrets.Port = "9091"
+	secrets.Scheme = "http"
+	ok, err := secrets.Configure(e)
+	assert.Nil(t, err)
+	assert.True(t, ok)
+
+	err = secrets.Apply(e)
+	assert.Nil(t, err)
+
+	assert.Empty(t, e.ApplicationProperties["quarkus.jaeger.enabled"])
+	assert.Equal(t, "test", e.ApplicationProperties["camel.vault.hashicorp.engine"])
+	assert.Equal(t, "my-hashicorp-vault-token", e.ApplicationProperties["camel.vault.hashicorp.token"])
+	assert.Equal(t, "localhost", e.ApplicationProperties["camel.vault.hashicorp.host"])
+	assert.Equal(t, "9091", e.ApplicationProperties["camel.vault.hashicorp.port"])
+	assert.Equal(t, "http", e.ApplicationProperties["camel.vault.hashicorp.scheme"])
+}
+
+func createEnvironment(t *testing.T, catalogGen func() (*camel.RuntimeCatalog, error), objects ...runtime.Object) *trait.Environment {
 	t.Helper()
 
 	catalog, err := catalogGen()
+	client, _ := test.NewFakeClient(objects...)
 	assert.Nil(t, err)
 
 	e := trait.Environment{
 		CamelCatalog:          catalog,
 		ApplicationProperties: make(map[string]string),
+		Client:                client,
 	}
 
 	it := v1.Integration{
 		ObjectMeta: metav1.ObjectMeta{
-			Name: "test",
+			Namespace: "test",
+			Name:      "test",
 		},
 		Status: v1.IntegrationStatus{
 			Phase: v1.IntegrationPhaseDeploying,
 		},
 	}
+	platform := v1.IntegrationPlatform{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: "test",
+			Name:      "test",
+		},
+	}
 	e.Integration = &it
+	e.Platform = &platform
 	return &e
 }
diff --git a/docs/modules/traits/pages/aws-secrets-manager.adoc b/docs/modules/traits/pages/aws-secrets-manager.adoc
index 4a67be3c1..d221f8280 100644
--- a/docs/modules/traits/pages/aws-secrets-manager.adoc
+++ b/docs/modules/traits/pages/aws-secrets-manager.adoc
@@ -50,8 +50,8 @@ Syntax: [configmap\|secret]:name[/key], where name represents the resource name,
 | aws-secrets-manager.secret-key
 | string
 | The AWS Secret Key to use. This could be a plain text or a configmap/secret
-	// The content of the aws secret key is expected to be a text containing a valid AWS secret key.
-	// Syntax: [configmap\|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = aws-secret-key).
+The content of the aws secret key is expected to be a text containing a valid AWS secret key.
+Syntax: [configmap\|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = aws-secret-key).
 
 | aws-secrets-manager.region
 | string
diff --git a/docs/modules/traits/pages/hashicorp-vault.adoc b/docs/modules/traits/pages/hashicorp-vault.adoc
index ea64b34e8..10c0cb89d 100644
--- a/docs/modules/traits/pages/hashicorp-vault.adoc
+++ b/docs/modules/traits/pages/hashicorp-vault.adoc
@@ -51,7 +51,9 @@ The following configuration options are available:
 
 | hashicorp-vault.token
 | string
-| The token to access Hashicorp Vault
+| The token to access Hashicorp Vault. This could be a plain text or a configmap/secret
+The content of the hashicorp vault token is expected to be a text containing a valid Hashicorp Vault Token.
+Syntax: [configmap\|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = hashicorp-vault-token).
 
 | hashicorp-vault.scheme
 | string
diff --git a/resources/traits.yaml b/resources/traits.yaml
index 826996269..887545196 100755
--- a/resources/traits.yaml
+++ b/resources/traits.yaml
@@ -116,11 +116,11 @@ traits:
       (default key value = aws-access-key).'
   - name: secret-key
     type: string
-    description: "The AWS Secret Key to use. This could be a plain text or a configmap/secret
-      \t// The content of the aws secret key is expected to be a text containing a
-      valid AWS secret key. \t// Syntax: [configmap|secret]:name[/key], where name
-      represents the resource name, key optionally represents the resource key to
-      be filtered (default key value = aws-secret-key)."
+    description: 'The AWS Secret Key to use. This could be a plain text or a configmap/secret
+      The content of the aws secret key is expected to be a text containing a valid
+      AWS secret key. Syntax: [configmap|secret]:name[/key], where name represents
+      the resource name, key optionally represents the resource key to be filtered
+      (default key value = aws-secret-key).'
   - name: region
     type: string
     description: The AWS Region to use
@@ -641,7 +641,11 @@ traits:
     description: The Hashicorp engine to use
   - name: token
     type: string
-    description: The token to access Hashicorp Vault
+    description: 'The token to access Hashicorp Vault. This could be a plain text
+      or a configmap/secret The content of the hashicorp vault token is expected to
+      be a text containing a valid Hashicorp Vault Token. Syntax: [configmap|secret]:name[/key],
+      where name represents the resource name, key optionally represents the resource
+      key to be filtered (default key value = hashicorp-vault-token).'
   - name: scheme
     type: string
     description: The scheme to access Hashicorp Vault