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 14:20:50 UTC
[camel-k] branch main updated: Kamelet - Inject secret in Vaults - Azure Key Vault (#4798)
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push:
new 062b21a09 Kamelet - Inject secret in Vaults - Azure Key Vault (#4798)
062b21a09 is described below
commit 062b21a09a96d734e886d1e9a0e49f4769dbce72
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Thu Oct 5 16:20:42 2023 +0200
Kamelet - Inject secret in Vaults - Azure Key Vault (#4798)
* Kamelet - Inject secret in Vaults - Azure Key Vault
Signed-off-by: Andrea Cosentino <an...@gmail.com>
* Kamelet - Inject secret in Vaults - Azure Key Vault
Signed-off-by: Andrea Cosentino <an...@gmail.com>
---------
Signed-off-by: Andrea Cosentino <an...@gmail.com>
---
addons/vault/azure/azure_key_vault.go | 36 ++++++-
addons/vault/azure/azure_key_vault_test.go | 110 ++++++++++++++++++++-
docs/modules/traits/pages/aws-secrets-manager.adoc | 4 +-
docs/modules/traits/pages/azure-key-vault.adoc | 8 +-
resources/traits.yaml | 25 +++--
5 files changed, 165 insertions(+), 18 deletions(-)
diff --git a/addons/vault/azure/azure_key_vault.go b/addons/vault/azure/azure_key_vault.go
index 76ecee985..5ab1ab0f6 100644
--- a/addons/vault/azure/azure_key_vault.go
+++ b/addons/vault/azure/azure_key_vault.go
@@ -18,8 +18,11 @@ limitations under the License.
package azure
import (
+ "regexp"
"strconv"
+ "github.com/apache/camel-k/v2/pkg/util/kubernetes"
+
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"
@@ -50,7 +53,9 @@ type Trait struct {
TenantID string `property:"tenant-id" json:"tenantId,omitempty"`
// The Azure Client Id for accessing Key Vault
ClientID string `property:"client-id" json:"clientId,omitempty"`
- // The Azure Client Secret for accessing Key Vault
+ // The Azure Client Secret for accessing Key Vault. This could be a plain text or a configmap/secret.
+ // The content of the azure key vault client secret is expected to be a text containing a valid Client Secret.
+ // Syntax: [configmap|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = azure-key-vault-client-secret).
ClientSecret string `property:"client-secret" json:"clientSecret,omitempty"`
// The Azure Vault Name for accessing Key Vault
VaultName string `property:"vault-name" json:"vaultName,omitempty"`
@@ -66,7 +71,9 @@ type Trait struct {
EventhubConnectionString string `property:"eventhub-connection-string" json:"eventhubConnectionString,omitempty"`
// If Refresh is enabled, the account name for Azure Storage Blob service used to save checkpoint while consuming from Eventhub
BlobAccountName string `property:"blob-account-name" json:"blobAccountName,omitempty"`
- // If Refresh is enabled, the access key for Azure Storage Blob service used to save checkpoint while consuming from Eventhub
+ // If Refresh is enabled, the access key for Azure Storage Blob service used to save checkpoint while consuming from Eventhub. This could be a plain text or a configmap/secret.
+ // The content of the azure key vault blob access key is expected to be a text containing a valid Access Key for Azure Storage Blob.
+ // Syntax: [configmap|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = azure-storage-blob-access-key).
BlobAccessKey string `property:"blob-access-key" json:"blobAccessKey,omitempty"`
// If Refresh is enabled, the container name for Azure Storage Blob service used to save checkpoint while consuming from Eventhub
BlobContainerName string `property:"blob-container-name" json:"blobContainerName,omitempty"`
@@ -104,6 +111,7 @@ func (t *azureKeyVaultTrait) Configure(environment *trait.Environment) (bool, er
}
func (t *azureKeyVaultTrait) 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.CapabilityAzureKeyVault)
// Deprecated
@@ -112,9 +120,30 @@ func (t *azureKeyVaultTrait) Apply(environment *trait.Environment) error {
}
if environment.IntegrationInRunningPhases() {
+ hits := rex.FindAllStringSubmatch(t.ClientSecret, -1)
+ if len(hits) >= 1 {
+ var res, _ = v1.DecodeValueSource(t.ClientSecret, "azure-key-vault-client-secret", "The Azure Key Vault Client Secret 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.azure.clientSecret"] = string([]byte(secretValue))
+ }
+ } else {
+ environment.ApplicationProperties["camel.vault.azure.clientSecret"] = t.ClientSecret
+ }
+ hits = rex.FindAllStringSubmatch(t.BlobAccessKey, -1)
+ if len(hits) >= 1 {
+ var res, _ = v1.DecodeValueSource(t.BlobAccessKey, "azure-storage-blob-access-key", "The Azure Storage Blob Access Key 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.azure.blobAccessKey"] = string([]byte(secretValue))
+ }
+ } else {
+ environment.ApplicationProperties["camel.vault.azure.blobAccessKey"] = t.BlobAccessKey
+ }
environment.ApplicationProperties["camel.vault.azure.tenantId"] = t.TenantID
environment.ApplicationProperties["camel.vault.azure.clientId"] = t.ClientID
- environment.ApplicationProperties["camel.vault.azure.clientSecret"] = t.ClientSecret
environment.ApplicationProperties["camel.vault.azure.vaultName"] = t.VaultName
environment.ApplicationProperties["camel.vault.azure.refreshEnabled"] = strconv.FormatBool(*t.RefreshEnabled)
environment.ApplicationProperties["camel.main.context-reload-enabled"] = strconv.FormatBool(*t.ContextReloadEnabled)
@@ -125,7 +154,6 @@ func (t *azureKeyVaultTrait) Apply(environment *trait.Environment) error {
environment.ApplicationProperties["camel.vault.azure.eventhubConnectionString"] = t.EventhubConnectionString
environment.ApplicationProperties["camel.vault.azure.blobAccountName"] = t.BlobAccountName
environment.ApplicationProperties["camel.vault.azure.blobContainerName"] = t.BlobContainerName
- environment.ApplicationProperties["camel.vault.azure.blobAccessKey"] = t.BlobAccessKey
}
return nil
diff --git a/addons/vault/azure/azure_key_vault_test.go b/addons/vault/azure/azure_key_vault_test.go
index 6de912212..388643605 100644
--- a/addons/vault/azure/azure_key_vault_test.go
+++ b/addons/vault/azure/azure_key_vault_test.go
@@ -20,6 +20,9 @@ package azure
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 TestAzureKeyVaultTraitApply(t *testing.T) {
@@ -52,25 +56,127 @@ func TestAzureKeyVaultTraitApply(t *testing.T) {
assert.Equal(t, "my-vault", e.ApplicationProperties["camel.vault.azure.vaultName"])
}
-func createEnvironment(t *testing.T, catalogGen func() (*camel.RuntimeCatalog, error)) *trait.Environment {
+func TestAzureKeyVaultTraitApplyWithConfigmapAndRefresh(t *testing.T) {
+ e := createEnvironment(t, camel.QuarkusCatalog, &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "my-configmap1",
+ },
+ Data: map[string]string{
+ "azure-client-secret": "my-secret-key",
+ },
+ }, &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "my-configmap2",
+ },
+ Data: map[string]string{
+ "azure-storage-blob-key": "my-access-key",
+ },
+ })
+ azure := NewAzureKeyVaultTrait()
+ secrets, _ := azure.(*azureKeyVaultTrait)
+ secrets.Enabled = pointer.Bool(true)
+ secrets.TenantID = "tenant-id"
+ secrets.ClientID = "client-id"
+ secrets.ClientSecret = "configmap:my-configmap1/azure-client-secret"
+ secrets.VaultName = "my-vault"
+ secrets.RefreshEnabled = pointer.Bool(true)
+ secrets.BlobAccessKey = "configmap:my-configmap2/azure-storage-blob-key"
+ secrets.BlobAccountName = "camel-k"
+ secrets.BlobContainerName = "camel-k-container"
+ ok, err := secrets.Configure(e)
+ assert.Nil(t, err)
+ assert.True(t, ok)
+
+ err = secrets.Apply(e)
+ assert.Nil(t, err)
+
+ assert.Equal(t, "client-id", e.ApplicationProperties["camel.vault.azure.clientId"])
+ assert.Equal(t, "my-secret-key", e.ApplicationProperties["camel.vault.azure.clientSecret"])
+ assert.Equal(t, "tenant-id", e.ApplicationProperties["camel.vault.azure.tenantId"])
+ assert.Equal(t, "my-vault", e.ApplicationProperties["camel.vault.azure.vaultName"])
+ assert.Equal(t, "camel-k", e.ApplicationProperties["camel.vault.azure.blobAccountName"])
+ assert.Equal(t, "camel-k-container", e.ApplicationProperties["camel.vault.azure.blobContainerName"])
+ assert.Equal(t, "my-access-key", e.ApplicationProperties["camel.vault.azure.blobAccessKey"])
+ assert.True(t, true, e.ApplicationProperties["camel.vault.azure.refreshEnabled"])
+}
+
+func TestAzureKeyVaultTraitApplyWithSecretAndRefresh(t *testing.T) {
+ e := createEnvironment(t, camel.QuarkusCatalog, &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "my-secret1",
+ },
+ Data: map[string][]byte{
+ "azure-client-secret": []byte("my-secret-key"),
+ },
+ }, &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "my-secret2",
+ },
+ Data: map[string][]byte{
+ "azure-storage-blob-key": []byte("my-access-key"),
+ },
+ })
+ azure := NewAzureKeyVaultTrait()
+ secrets, _ := azure.(*azureKeyVaultTrait)
+ secrets.Enabled = pointer.Bool(true)
+ secrets.TenantID = "tenant-id"
+ secrets.ClientID = "client-id"
+ secrets.ClientSecret = "secret:my-secret1/azure-client-secret"
+ secrets.VaultName = "my-vault"
+ secrets.RefreshEnabled = pointer.Bool(true)
+ secrets.BlobAccessKey = "secret:my-secret2/azure-storage-blob-key"
+ secrets.BlobAccountName = "camel-k"
+ secrets.BlobContainerName = "camel-k-container"
+ ok, err := secrets.Configure(e)
+ assert.Nil(t, err)
+ assert.True(t, ok)
+
+ err = secrets.Apply(e)
+ assert.Nil(t, err)
+
+ assert.Equal(t, "client-id", e.ApplicationProperties["camel.vault.azure.clientId"])
+ assert.Equal(t, "my-secret-key", e.ApplicationProperties["camel.vault.azure.clientSecret"])
+ assert.Equal(t, "tenant-id", e.ApplicationProperties["camel.vault.azure.tenantId"])
+ assert.Equal(t, "my-vault", e.ApplicationProperties["camel.vault.azure.vaultName"])
+ assert.Equal(t, "camel-k", e.ApplicationProperties["camel.vault.azure.blobAccountName"])
+ assert.Equal(t, "camel-k-container", e.ApplicationProperties["camel.vault.azure.blobContainerName"])
+ assert.Equal(t, "my-access-key", e.ApplicationProperties["camel.vault.azure.blobAccessKey"])
+ assert.True(t, true, e.ApplicationProperties["camel.vault.azure.refreshEnabled"])
+}
+
+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/azure-key-vault.adoc b/docs/modules/traits/pages/azure-key-vault.adoc
index 48303a037..a5d8ffc69 100644
--- a/docs/modules/traits/pages/azure-key-vault.adoc
+++ b/docs/modules/traits/pages/azure-key-vault.adoc
@@ -51,7 +51,9 @@ The following configuration options are available:
| azure-key-vault.client-secret
| string
-| The Azure Client Secret for accessing Key Vault
+| The Azure Client Secret for accessing Key Vault. This could be a plain text or a configmap/secret.
+The content of the azure key vault client secret is expected to be a text containing a valid Client Secret.
+Syntax: [configmap\|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = azure-key-vault-client-secret).
| azure-key-vault.vault-name
| string
@@ -83,7 +85,9 @@ The following configuration options are available:
| azure-key-vault.blob-access-key
| string
-| If Refresh is enabled, the access key for Azure Storage Blob service used to save checkpoint while consuming from Eventhub
+| If Refresh is enabled, the access key for Azure Storage Blob service used to save checkpoint while consuming from Eventhub. This could be a plain text or a configmap/secret.
+The content of the azure key vault blob access key is expected to be a text containing a valid Access Key for Azure Storage Blob.
+Syntax: [configmap\|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = azure-storage-blob-access-key).
| azure-key-vault.blob-container-name
| string
diff --git a/resources/traits.yaml b/resources/traits.yaml
index 826996269..5fdd4f75e 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
@@ -179,7 +179,11 @@ traits:
description: The Azure Client Id for accessing Key Vault
- name: client-secret
type: string
- description: The Azure Client Secret for accessing Key Vault
+ description: 'The Azure Client Secret for accessing Key Vault. This could be a
+ plain text or a configmap/secret. The content of the azure key vault client
+ secret is expected to be a text containing a valid Client Secret. Syntax: [configmap|secret]:name[/key],
+ where name represents the resource name, key optionally represents the resource
+ key to be filtered (default key value = azure-key-vault-client-secret).'
- name: vault-name
type: string
description: The Azure Vault Name for accessing Key Vault
@@ -207,8 +211,13 @@ traits:
used to save checkpoint while consuming from Eventhub
- name: blob-access-key
type: string
- description: If Refresh is enabled, the access key for Azure Storage Blob service
- used to save checkpoint while consuming from Eventhub
+ description: 'If Refresh is enabled, the access key for Azure Storage Blob service
+ used to save checkpoint while consuming from Eventhub. This could be a plain
+ text or a configmap/secret. The content of the azure key vault blob access key
+ is expected to be a text containing a valid Access Key for Azure Storage Blob.
+ Syntax: [configmap|secret]:name[/key], where name represents the resource name,
+ key optionally represents the resource key to be filtered (default key value
+ = azure-storage-blob-access-key).'
- name: blob-container-name
type: string
description: If Refresh is enabled, the container name for Azure Storage Blob