From 62afbca2055ff4d565c1614a4585d63abe9e5d30 Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Wed, 11 Nov 2026 17:44:11 +0100 Subject: [PATCH 1/2] CAMEL-25675: camel-hashicorp-vault - AWS IAM, Azure managed identity and GCP Compute Engine logins The endpoint, the hashicorp: properties function and the secret refresh task can log in with the identity the cloud gives the application: aws-iam (the AWS SDK default credentials chain, with awsRegion, awsStsEndpoint and awsIamServerId; the AWS SDK auth module is an optional dependency, used only by this login), azure-msi (the managed identity token for azureResource, by default https://management.azure.com/, and azureClientId for a user-assigned identity) and gcp-gce (the service account of the Compute Engine instance). The metadata services are called without a proxy. The review of the TLS change: the role, authMountPath and keyStore descriptions cover the cert login and PKCS#1, the docs say the stores are read when the client is created, a trust store that reads as empty fails with a hint about its password, and a test reads an EC key. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Andrea Cosentino --- .../catalog/components/hashicorp-vault.json | 29 +-- .../docs/hashicorp-vault-component.adoc | 46 +++- .../org/apache/camel/catalog/docs/main.adoc | 15 +- .../camel-main-configuration-metadata.json | 13 +- components/camel-hashicorp-vault/pom.xml | 8 + .../HashicorpVaultEndpointConfigurer.java | 30 +++ .../HashicorpVaultEndpointUriFactory.java | 7 +- .../hashicorp/vault/hashicorp-vault.json | 29 +-- .../main/docs/hashicorp-vault-component.adoc | 46 +++- .../vault/HashicorpVaultAuthentication.java | 5 +- .../hashicorp/vault/HashicorpVaultAwsIam.java | 72 +++++++ .../hashicorp/vault/HashicorpVaultClient.java | 121 ++++++++++- .../vault/HashicorpVaultClientSettings.java | 65 +++++- .../vault/HashicorpVaultConfiguration.java | 89 +++++++- .../vault/HashicorpVaultEndpoint.java | 5 + .../HashicorpVaultPropertiesFunction.java | 16 +- .../hashicorp/vault/HashicorpVaultTls.java | 11 +- .../HashicorpVaultClientSettingsTest.java | 42 ++++ .../vault/HashicorpVaultClientTest.java | 4 +- .../vault/HashicorpVaultCloudLoginTest.java | 198 ++++++++++++++++++ .../vault/HashicorpVaultTlsTest.java | 27 ++- .../hashicorp/vault/tls/client-ec.pem | 16 ++ .../vault/HashicorpVaultConfiguration.java | 114 +++++++++- ...HashicorpVaultConfigurationConfigurer.java | 30 +++ ...aultConfigurationPropertiesConfigurer.java | 35 ++++ .../camel-main-configuration-metadata.json | 13 +- core/camel-main/src/main/docs/main.adoc | 15 +- ...HashicorpVaultConfigurationProperties.java | 44 +++- .../modules/ROOT/pages/security.adoc | 3 +- .../HashicorpVaultEndpointBuilderFactory.java | 104 ++++++++- 30 files changed, 1159 insertions(+), 93 deletions(-) create mode 100644 components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java create mode 100644 components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java create mode 100644 components/camel-hashicorp-vault/src/test/resources/org/apache/camel/component/hashicorp/vault/tls/client-ec.pem diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json index ec3a121a81eb7..58915e6abd535 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json @@ -48,17 +48,22 @@ "secretPath": { "index": 7, "kind": "parameter", "displayName": "Secret Path", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Hashicorp Vault instance secret Path to be used" }, "vaultTemplate": { "index": 8, "kind": "parameter", "displayName": "Vault Template", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.springframework.vault.core.VaultTemplate", "deprecated": false, "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Instance of Vault template" }, "lazyStartProducer": { "index": 9, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "authentication": { "index": 10, "kind": "parameter", "displayName": "Authentication", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "token", "approle", "kubernetes", "jwt", "cert" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "token", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "How to log in to HashiCorp Vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client certificate of the keyStore). The token is renewed before it expires, and the endpoint logs in again when the token can no longer be renewed." }, - "authMountPath": { "index": 11, "kind": "parameter", "displayName": "Auth Mount Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The path the login method is mounted at in HashiCorp Vault (without auth\/), when it is not the default path of the login method: approle, kubernetes or jwt" }, - "jwt": { "index": 12, "kind": "parameter", "displayName": "Jwt", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead." }, - "jwtFile": { "index": 13, "kind": "parameter", "displayName": "Jwt File", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set." }, - "keyStore": { "index": 14, "kind": "parameter", "displayName": "Key Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the TLS client certificate and its private key, which the endpoint presents to HashiCorp Vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and the PKCS#8 private key." }, - "keyStorePassword": { "index": 15, "kind": "parameter", "displayName": "Key Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store" }, - "role": { "index": 16, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the login method has a default role." }, - "roleId": { "index": 17, "kind": "parameter", "displayName": "Role Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The role ID of the AppRole, for the approle login" }, - "secretId": { "index": 18, "kind": "parameter", "displayName": "Secret Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The secret ID of the AppRole, for the approle login" }, - "token": { "index": 19, "kind": "parameter", "displayName": "Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Token to be used, for the token login" }, - "trustStore": { "index": 20, "kind": "parameter", "displayName": "Trust Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the certificates to trust for the TLS connection to HashiCorp Vault, such as the CA certificate of a private CA: a PKCS12 or JKS trust store, or PEM certificates. When not set, the JVM trusts the certificate as for any other TLS connection." }, - "trustStorePassword": { "index": 21, "kind": "parameter", "displayName": "Trust Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the trust store, when it is a PKCS12 or JKS trust store" } + "authentication": { "index": 10, "kind": "parameter", "displayName": "Authentication", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "token", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "How to log in to HashiCorp Vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). The token is renewed before it expires, and the endpoint logs in again when the token can no longer be renewed." }, + "authMountPath": { "index": 11, "kind": "parameter", "displayName": "Auth Mount Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The path the login method is mounted at in HashiCorp Vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)" }, + "awsIamServerId": { "index": 12, "kind": "parameter", "displayName": "Aws Iam Server Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of HashiCorp Vault requires one (iam_server_id_header_value)" }, + "awsRegion": { "index": 13, "kind": "parameter", "displayName": "Aws Region", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable)." }, + "awsStsEndpoint": { "index": 14, "kind": "parameter", "displayName": "Aws Sts Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of HashiCorp Vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/." }, + "azureClientId": { "index": 15, "kind": "parameter", "displayName": "Azure Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity." }, + "azureResource": { "index": 16, "kind": "parameter", "displayName": "Azure Resource", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "https:\/\/management.azure.com\/", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of HashiCorp Vault" }, + "jwt": { "index": 17, "kind": "parameter", "displayName": "Jwt", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead." }, + "jwtFile": { "index": 18, "kind": "parameter", "displayName": "Jwt File", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set." }, + "keyStore": { "index": 19, "kind": "parameter", "displayName": "Key Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the TLS client certificate and its private key, which the endpoint presents to HashiCorp Vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1." }, + "keyStorePassword": { "index": 20, "kind": "parameter", "displayName": "Key Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store" }, + "role": { "index": 21, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate." }, + "roleId": { "index": 22, "kind": "parameter", "displayName": "Role Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The role ID of the AppRole, for the approle login" }, + "secretId": { "index": 23, "kind": "parameter", "displayName": "Secret Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The secret ID of the AppRole, for the approle login" }, + "token": { "index": 24, "kind": "parameter", "displayName": "Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Token to be used, for the token login" }, + "trustStore": { "index": 25, "kind": "parameter", "displayName": "Trust Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the certificates to trust for the TLS connection to HashiCorp Vault, such as the CA certificate of a private CA: a PKCS12 or JKS trust store, or PEM certificates. When not set, the JVM trusts the certificate as for any other TLS connection." }, + "trustStorePassword": { "index": 26, "kind": "parameter", "displayName": "Trust Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the trust store, when it is a PKCS12 or JKS trust store" } } } diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc index 96c9c343121a0..00b6bfb15a7e0 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc @@ -78,10 +78,20 @@ JWT login of Vault has a default role. | `cert` | `keyStore`: the TLS client certificate, see <>. `role` is the name of the certificate role in Vault; without it, Vault tries every certificate role that trusts the certificate. The login needs the `https` scheme. + +| `aws-iam` +| `role`: the Vault role of the application, which logs in with its AWS credentials, see <>. + +| `azure-msi` +| `role`: the Vault role of the application, which logs in with its Azure managed identity, see <>. + +| `gcp-gce` +| `role`: the Vault role of the application, which logs in with the service account of its Google Compute Engine +instance, see <>. |=== -When the login method is not mounted at its default path in Vault (`approle`, `kubernetes`, `jwt` or `cert`), set the -path with `authMountPath`, without `auth/`. +When the login method is not mounted at its default path in Vault (`approle`, `kubernetes`, `jwt`, `cert`, `aws` for +`aws-iam`, `azure` for `azure-msi` or `gcp` for `gcp-gce`), set the path with `authMountPath`, without `auth/`. Camel renews the token before it expires, and logs in again when the token can no longer be renewed, such as when it reached its maximum time to live. A JWT read from a file is read again at every login, so a token that the platform @@ -113,6 +123,10 @@ To present a client certificate to Vault, for the `cert` login or for a Vault th key. The key of a PEM file is not encrypted, in PKCS#8 (`-----BEGIN PRIVATE KEY-----`) or, for an RSA key, in PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`). +The trust store and the key store are read when the client is created, when the endpoint, the properties function or +the secret refresh task starts. A certificate replaced in its file, such as a client certificate renewed before it +expires, is used after a restart. + For example, the properties function logs in with a client certificate: [source,properties] @@ -126,6 +140,30 @@ camel.vault.hashicorp.role = my-application camel.vault.hashicorp.keyStore = /etc/vault/client.pem ---- +=== Cloud logins + +The `aws-iam` login signs a request to AWS STS with the credentials of the AWS SDK default chain: the environment +variables, the system properties, a web identity token (such as IAM roles for service accounts on Amazon EKS), the +profile, the container credentials (Amazon ECS) or the instance profile (Amazon EC2). Vault checks the request with +STS. The login needs the AWS SDK: add the `software.amazon.awssdk:auth` dependency, in the version of the AWS SDK of +the Camel AWS components. The request is sent to `awsStsEndpoint`, by default the global endpoint +`https://sts.amazonaws.com/`, and signed for `awsRegion`, by default the region of the AWS SDK default region chain +(such as the `AWS_REGION` environment variable). The global endpoint takes requests signed for `us-east-1`; to use a +regional endpoint, set it with its region, as the AWS login of Vault is configured (`sts_endpoint` and `sts_region`). +`awsIamServerId` sets the `X-Vault-AWS-IAM-Server-ID` header, when the AWS login of Vault requires one. + +The `azure-msi` login asks the Azure instance metadata service (`169.254.169.254`) for a token of the managed identity +of the virtual machine, for the resource `azureResource`, by default `https://management.azure.com/`, which must be +the resource of the Azure login of Vault (`auth/azure/config`). `azureClientId` chooses a user-assigned managed +identity, instead of the system-assigned one. The instance metadata service is on Azure virtual machines and scale +sets. A pod of Azure Kubernetes Service with workload identity has a token in the file named by the +`AZURE_FEDERATED_TOKEN_FILE` environment variable instead, for the `jwt` login with `jwtFile`. + +The `gcp-gce` login asks the metadata server of a Google Compute Engine instance for an identity token of the default +service account of the instance, for a role of type `gce` of the GCP login of Vault. + +The metadata services are reached directly, never through an HTTP proxy. + === OpenBao The component, the properties function and the secret refresh task also work with https://openbao.org/[OpenBao], the @@ -420,7 +458,9 @@ The properties function also reads these options from the environment variables `CAMEL_HASHICORP_VAULT_ROLE`, `CAMEL_HASHICORP_VAULT_JWT`, `CAMEL_HASHICORP_VAULT_JWT_FILE` and `CAMEL_HASHICORP_VAULT_AUTH_MOUNT_PATH`, and the settings of <> from `CAMEL_HASHICORP_VAULT_TRUST_STORE`, `CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD`, `CAMEL_HASHICORP_VAULT_KEY_STORE` and -`CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the +`CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`, and the settings of the <> from +`CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID`, `CAMEL_HASHICORP_VAULT_AWS_REGION`, `CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT`, +`CAMEL_HASHICORP_VAULT_AZURE_RESOURCE` and `CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the properties function takes all its settings from the environment variables, and none from the `camel.vault.hashicorp` configuration. The secret refresh task logs in the same way as the properties function. diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc index ebbbbfb72fe8c..5c0ec3dc0f216 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc @@ -542,24 +542,29 @@ The camel.vault.kubernetescm supports 2 options, which are listed below. === Camel Hashicorp Vault configurations -The camel.vault.hashicorp supports 20 options, which are listed below. +The camel.vault.hashicorp supports 25 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== | Name | Description | Default | Type -| `camel.vault.hashicorp.authentication` | How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client certificate of the keyStore). Camel renews the token before it expires, and logs in again when the token can no longer be renewed. | token | String -| `camel.vault.hashicorp.authMountPath` | The path the login method is mounted at in hashicorp vault (without auth/), when it is not the default path of the login method: approle, kubernetes or jwt | | String +| `camel.vault.hashicorp.authentication` | How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed. | token | String +| `camel.vault.hashicorp.authMountPath` | The path the login method is mounted at in hashicorp vault (without auth/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce) | | String +| `camel.vault.hashicorp.awsIamServerId` | The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value) | | String +| `camel.vault.hashicorp.awsRegion` | The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable). | | String +| `camel.vault.hashicorp.awsStsEndpoint` | The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint \https://sts.amazonaws.com/. | | String +| `camel.vault.hashicorp.azureClientId` | The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity. | | String +| `camel.vault.hashicorp.azureResource` | The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault | https://management.azure.com/ | String | `camel.vault.hashicorp.cloud` | Determine if the Hashicorp Vault is deployed on Hashicorp Cloud or not | false | boolean | `camel.vault.hashicorp.host` | Host to access hashicorp vault | | String | `camel.vault.hashicorp.jwt` | The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead. | | String | `camel.vault.hashicorp.jwtFile` | The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads /var/run/secrets/kubernetes.io/serviceaccount/token when neither jwt nor jwtFile is set. | | String -| `camel.vault.hashicorp.keyStore` | The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and the PKCS#8 private key. | | String +| `camel.vault.hashicorp.keyStore` | The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1. | | String | `camel.vault.hashicorp.keyStorePassword` | The password of the key store and of its private key, when it is a PKCS12 or JKS key store | | String | `camel.vault.hashicorp.namespace` | If the Hashicorp Vault instance is deployed on Hashicorp Cloud, this field will determine the namespace | | String | `camel.vault.hashicorp.port` | Port to access hashicorp vault | | String | `camel.vault.hashicorp.refreshEnabled` | Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault. | false | boolean | `camel.vault.hashicorp.refreshPeriod` | The period (millis) between checking Hashicorp Vault for updated secrets. | 60000 | long -| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the login method has a default role. | | String +| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate. | | String | `camel.vault.hashicorp.roleId` | The role ID of the AppRole, for the approle login | | String | `camel.vault.hashicorp.scheme` | Scheme to access hashicorp vault | | String | `camel.vault.hashicorp.secretId` | The secret ID of the AppRole, for the approle login | | String diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json index 1b2d7a784d632..92da963c36b85 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json @@ -591,19 +591,24 @@ { "name": "camel.vault.gcp.serviceAccountKey", "required": false, "description": "The Service Account Key location", "sourceType": "org.apache.camel.vault.GcpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.gcp.subscriptionName", "required": false, "description": "Define the Google Pubsub subscription Name to be used when checking for updates", "sourceType": "org.apache.camel.vault.GcpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.gcp.useDefaultInstance", "required": false, "description": "Define if we want to use the GCP Client Default Instance or not", "sourceType": "org.apache.camel.vault.GcpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, - { "name": "camel.vault.hashicorp.authentication", "required": false, "description": "How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client certificate of the keyStore). Camel renews the token before it expires, and logs in again when the token can no longer be renewed.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "enum", "javaType": "java.lang.String", "defaultValue": "token", "secret": false, "enum": [ "token", "approle", "kubernetes", "jwt", "cert" ] }, - { "name": "camel.vault.hashicorp.authMountPath", "required": false, "description": "The path the login method is mounted at in hashicorp vault (without auth\/), when it is not the default path of the login method: approle, kubernetes or jwt", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.authentication", "required": false, "description": "How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "enum", "javaType": "java.lang.String", "defaultValue": "token", "secret": false, "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ] }, + { "name": "camel.vault.hashicorp.authMountPath", "required": false, "description": "The path the login method is mounted at in hashicorp vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsIamServerId", "required": false, "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsRegion", "required": false, "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable).", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsStsEndpoint", "required": false, "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.azureClientId", "required": false, "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.azureResource", "required": false, "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "defaultValue": "https:\/\/management.azure.com\/", "secret": false }, { "name": "camel.vault.hashicorp.cloud", "required": false, "description": "Determine if the Hashicorp Vault is deployed on Hashicorp Cloud or not", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.vault.hashicorp.host", "required": true, "description": "Host to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.jwt", "required": false, "description": "The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.jwtFile", "required": false, "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, - { "name": "camel.vault.hashicorp.keyStore", "required": false, "description": "The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and the PKCS#8 private key.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.keyStore", "required": false, "description": "The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.keyStorePassword", "required": false, "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.namespace", "required": false, "description": "If the Hashicorp Vault instance is deployed on Hashicorp Cloud, this field will determine the namespace", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.port", "required": true, "description": "Port to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.refreshEnabled", "required": false, "description": "Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.vault.hashicorp.refreshPeriod", "required": false, "description": "The period (millis) between checking Hashicorp Vault for updated secrets.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "integer", "javaType": "long", "defaultValue": 60000, "secret": false }, - { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the login method has a default role.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.roleId", "required": false, "description": "The role ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.scheme", "required": true, "description": "Scheme to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.secretId", "required": false, "description": "The secret ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, diff --git a/components/camel-hashicorp-vault/pom.xml b/components/camel-hashicorp-vault/pom.xml index 48ba4831ead8c..41d2fda85d487 100644 --- a/components/camel-hashicorp-vault/pom.xml +++ b/components/camel-hashicorp-vault/pom.xml @@ -54,6 +54,14 @@ jackson-databind + + + software.amazon.awssdk + auth + ${aws-java-sdk2-version} + true + + org.apache.camel diff --git a/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointConfigurer.java b/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointConfigurer.java index b362005a87b93..938a441c1e074 100644 --- a/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointConfigurer.java +++ b/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointConfigurer.java @@ -27,6 +27,16 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "authmountpath": case "authMountPath": target.getConfiguration().setAuthMountPath(property(camelContext, java.lang.String.class, value)); return true; case "authentication": target.getConfiguration().setAuthentication(property(camelContext, java.lang.String.class, value)); return true; + case "awsiamserverid": + case "awsIamServerId": target.getConfiguration().setAwsIamServerId(property(camelContext, java.lang.String.class, value)); return true; + case "awsregion": + case "awsRegion": target.getConfiguration().setAwsRegion(property(camelContext, java.lang.String.class, value)); return true; + case "awsstsendpoint": + case "awsStsEndpoint": target.getConfiguration().setAwsStsEndpoint(property(camelContext, java.lang.String.class, value)); return true; + case "azureclientid": + case "azureClientId": target.getConfiguration().setAzureClientId(property(camelContext, java.lang.String.class, value)); return true; + case "azureresource": + case "azureResource": target.getConfiguration().setAzureResource(property(camelContext, java.lang.String.class, value)); return true; case "cloud": target.getConfiguration().setCloud(property(camelContext, boolean.class, value)); return true; case "host": target.getConfiguration().setHost(property(camelContext, java.lang.String.class, value)); return true; case "jwt": target.getConfiguration().setJwt(property(camelContext, java.lang.String.class, value)); return true; @@ -71,6 +81,16 @@ public Class getOptionType(String name, boolean ignoreCase) { case "authmountpath": case "authMountPath": return java.lang.String.class; case "authentication": return java.lang.String.class; + case "awsiamserverid": + case "awsIamServerId": return java.lang.String.class; + case "awsregion": + case "awsRegion": return java.lang.String.class; + case "awsstsendpoint": + case "awsStsEndpoint": return java.lang.String.class; + case "azureclientid": + case "azureClientId": return java.lang.String.class; + case "azureresource": + case "azureResource": return java.lang.String.class; case "cloud": return boolean.class; case "host": return java.lang.String.class; case "jwt": return java.lang.String.class; @@ -111,6 +131,16 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "authmountpath": case "authMountPath": return target.getConfiguration().getAuthMountPath(); case "authentication": return target.getConfiguration().getAuthentication(); + case "awsiamserverid": + case "awsIamServerId": return target.getConfiguration().getAwsIamServerId(); + case "awsregion": + case "awsRegion": return target.getConfiguration().getAwsRegion(); + case "awsstsendpoint": + case "awsStsEndpoint": return target.getConfiguration().getAwsStsEndpoint(); + case "azureclientid": + case "azureClientId": return target.getConfiguration().getAzureClientId(); + case "azureresource": + case "azureResource": return target.getConfiguration().getAzureResource(); case "cloud": return target.getConfiguration().isCloud(); case "host": return target.getConfiguration().getHost(); case "jwt": return target.getConfiguration().getJwt(); diff --git a/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointUriFactory.java b/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointUriFactory.java index d280e3141d65e..0f6a4466cd4a0 100644 --- a/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointUriFactory.java +++ b/components/camel-hashicorp-vault/src/generated/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpointUriFactory.java @@ -24,9 +24,14 @@ public class HashicorpVaultEndpointUriFactory extends org.apache.camel.support.c private static final Set ENDPOINT_IDENTITY_PROPERTY_NAMES; private static final Map MULTI_VALUE_PREFIXES; static { - Set props = new HashSet<>(22); + Set props = new HashSet<>(27); props.add("authMountPath"); props.add("authentication"); + props.add("awsIamServerId"); + props.add("awsRegion"); + props.add("awsStsEndpoint"); + props.add("azureClientId"); + props.add("azureResource"); props.add("cloud"); props.add("host"); props.add("jwt"); diff --git a/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json b/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json index ec3a121a81eb7..58915e6abd535 100644 --- a/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json +++ b/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json @@ -48,17 +48,22 @@ "secretPath": { "index": 7, "kind": "parameter", "displayName": "Secret Path", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Hashicorp Vault instance secret Path to be used" }, "vaultTemplate": { "index": 8, "kind": "parameter", "displayName": "Vault Template", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.springframework.vault.core.VaultTemplate", "deprecated": false, "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Instance of Vault template" }, "lazyStartProducer": { "index": 9, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "authentication": { "index": 10, "kind": "parameter", "displayName": "Authentication", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "token", "approle", "kubernetes", "jwt", "cert" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "token", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "How to log in to HashiCorp Vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client certificate of the keyStore). The token is renewed before it expires, and the endpoint logs in again when the token can no longer be renewed." }, - "authMountPath": { "index": 11, "kind": "parameter", "displayName": "Auth Mount Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The path the login method is mounted at in HashiCorp Vault (without auth\/), when it is not the default path of the login method: approle, kubernetes or jwt" }, - "jwt": { "index": 12, "kind": "parameter", "displayName": "Jwt", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead." }, - "jwtFile": { "index": 13, "kind": "parameter", "displayName": "Jwt File", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set." }, - "keyStore": { "index": 14, "kind": "parameter", "displayName": "Key Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the TLS client certificate and its private key, which the endpoint presents to HashiCorp Vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and the PKCS#8 private key." }, - "keyStorePassword": { "index": 15, "kind": "parameter", "displayName": "Key Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store" }, - "role": { "index": 16, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the login method has a default role." }, - "roleId": { "index": 17, "kind": "parameter", "displayName": "Role Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The role ID of the AppRole, for the approle login" }, - "secretId": { "index": 18, "kind": "parameter", "displayName": "Secret Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The secret ID of the AppRole, for the approle login" }, - "token": { "index": 19, "kind": "parameter", "displayName": "Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Token to be used, for the token login" }, - "trustStore": { "index": 20, "kind": "parameter", "displayName": "Trust Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the certificates to trust for the TLS connection to HashiCorp Vault, such as the CA certificate of a private CA: a PKCS12 or JKS trust store, or PEM certificates. When not set, the JVM trusts the certificate as for any other TLS connection." }, - "trustStorePassword": { "index": 21, "kind": "parameter", "displayName": "Trust Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the trust store, when it is a PKCS12 or JKS trust store" } + "authentication": { "index": 10, "kind": "parameter", "displayName": "Authentication", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "token", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "How to log in to HashiCorp Vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). The token is renewed before it expires, and the endpoint logs in again when the token can no longer be renewed." }, + "authMountPath": { "index": 11, "kind": "parameter", "displayName": "Auth Mount Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The path the login method is mounted at in HashiCorp Vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)" }, + "awsIamServerId": { "index": 12, "kind": "parameter", "displayName": "Aws Iam Server Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of HashiCorp Vault requires one (iam_server_id_header_value)" }, + "awsRegion": { "index": 13, "kind": "parameter", "displayName": "Aws Region", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable)." }, + "awsStsEndpoint": { "index": 14, "kind": "parameter", "displayName": "Aws Sts Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of HashiCorp Vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/." }, + "azureClientId": { "index": 15, "kind": "parameter", "displayName": "Azure Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity." }, + "azureResource": { "index": 16, "kind": "parameter", "displayName": "Azure Resource", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "https:\/\/management.azure.com\/", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of HashiCorp Vault" }, + "jwt": { "index": 17, "kind": "parameter", "displayName": "Jwt", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead." }, + "jwtFile": { "index": 18, "kind": "parameter", "displayName": "Jwt File", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set." }, + "keyStore": { "index": 19, "kind": "parameter", "displayName": "Key Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the TLS client certificate and its private key, which the endpoint presents to HashiCorp Vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1." }, + "keyStorePassword": { "index": 20, "kind": "parameter", "displayName": "Key Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store" }, + "role": { "index": 21, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate." }, + "roleId": { "index": 22, "kind": "parameter", "displayName": "Role Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The role ID of the AppRole, for the approle login" }, + "secretId": { "index": 23, "kind": "parameter", "displayName": "Secret Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The secret ID of the AppRole, for the approle login" }, + "token": { "index": 24, "kind": "parameter", "displayName": "Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Token to be used, for the token login" }, + "trustStore": { "index": 25, "kind": "parameter", "displayName": "Trust Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the certificates to trust for the TLS connection to HashiCorp Vault, such as the CA certificate of a private CA: a PKCS12 or JKS trust store, or PEM certificates. When not set, the JVM trusts the certificate as for any other TLS connection." }, + "trustStorePassword": { "index": 26, "kind": "parameter", "displayName": "Trust Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the trust store, when it is a PKCS12 or JKS trust store" } } } diff --git a/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc b/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc index 96c9c343121a0..00b6bfb15a7e0 100644 --- a/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc +++ b/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc @@ -78,10 +78,20 @@ JWT login of Vault has a default role. | `cert` | `keyStore`: the TLS client certificate, see <>. `role` is the name of the certificate role in Vault; without it, Vault tries every certificate role that trusts the certificate. The login needs the `https` scheme. + +| `aws-iam` +| `role`: the Vault role of the application, which logs in with its AWS credentials, see <>. + +| `azure-msi` +| `role`: the Vault role of the application, which logs in with its Azure managed identity, see <>. + +| `gcp-gce` +| `role`: the Vault role of the application, which logs in with the service account of its Google Compute Engine +instance, see <>. |=== -When the login method is not mounted at its default path in Vault (`approle`, `kubernetes`, `jwt` or `cert`), set the -path with `authMountPath`, without `auth/`. +When the login method is not mounted at its default path in Vault (`approle`, `kubernetes`, `jwt`, `cert`, `aws` for +`aws-iam`, `azure` for `azure-msi` or `gcp` for `gcp-gce`), set the path with `authMountPath`, without `auth/`. Camel renews the token before it expires, and logs in again when the token can no longer be renewed, such as when it reached its maximum time to live. A JWT read from a file is read again at every login, so a token that the platform @@ -113,6 +123,10 @@ To present a client certificate to Vault, for the `cert` login or for a Vault th key. The key of a PEM file is not encrypted, in PKCS#8 (`-----BEGIN PRIVATE KEY-----`) or, for an RSA key, in PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`). +The trust store and the key store are read when the client is created, when the endpoint, the properties function or +the secret refresh task starts. A certificate replaced in its file, such as a client certificate renewed before it +expires, is used after a restart. + For example, the properties function logs in with a client certificate: [source,properties] @@ -126,6 +140,30 @@ camel.vault.hashicorp.role = my-application camel.vault.hashicorp.keyStore = /etc/vault/client.pem ---- +=== Cloud logins + +The `aws-iam` login signs a request to AWS STS with the credentials of the AWS SDK default chain: the environment +variables, the system properties, a web identity token (such as IAM roles for service accounts on Amazon EKS), the +profile, the container credentials (Amazon ECS) or the instance profile (Amazon EC2). Vault checks the request with +STS. The login needs the AWS SDK: add the `software.amazon.awssdk:auth` dependency, in the version of the AWS SDK of +the Camel AWS components. The request is sent to `awsStsEndpoint`, by default the global endpoint +`https://sts.amazonaws.com/`, and signed for `awsRegion`, by default the region of the AWS SDK default region chain +(such as the `AWS_REGION` environment variable). The global endpoint takes requests signed for `us-east-1`; to use a +regional endpoint, set it with its region, as the AWS login of Vault is configured (`sts_endpoint` and `sts_region`). +`awsIamServerId` sets the `X-Vault-AWS-IAM-Server-ID` header, when the AWS login of Vault requires one. + +The `azure-msi` login asks the Azure instance metadata service (`169.254.169.254`) for a token of the managed identity +of the virtual machine, for the resource `azureResource`, by default `https://management.azure.com/`, which must be +the resource of the Azure login of Vault (`auth/azure/config`). `azureClientId` chooses a user-assigned managed +identity, instead of the system-assigned one. The instance metadata service is on Azure virtual machines and scale +sets. A pod of Azure Kubernetes Service with workload identity has a token in the file named by the +`AZURE_FEDERATED_TOKEN_FILE` environment variable instead, for the `jwt` login with `jwtFile`. + +The `gcp-gce` login asks the metadata server of a Google Compute Engine instance for an identity token of the default +service account of the instance, for a role of type `gce` of the GCP login of Vault. + +The metadata services are reached directly, never through an HTTP proxy. + === OpenBao The component, the properties function and the secret refresh task also work with https://openbao.org/[OpenBao], the @@ -420,7 +458,9 @@ The properties function also reads these options from the environment variables `CAMEL_HASHICORP_VAULT_ROLE`, `CAMEL_HASHICORP_VAULT_JWT`, `CAMEL_HASHICORP_VAULT_JWT_FILE` and `CAMEL_HASHICORP_VAULT_AUTH_MOUNT_PATH`, and the settings of <> from `CAMEL_HASHICORP_VAULT_TRUST_STORE`, `CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD`, `CAMEL_HASHICORP_VAULT_KEY_STORE` and -`CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the +`CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`, and the settings of the <> from +`CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID`, `CAMEL_HASHICORP_VAULT_AWS_REGION`, `CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT`, +`CAMEL_HASHICORP_VAULT_AZURE_RESOURCE` and `CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the properties function takes all its settings from the environment variables, and none from the `camel.vault.hashicorp` configuration. The secret refresh task logs in the same way as the properties function. diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAuthentication.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAuthentication.java index b649820f09e83..bb271d2a31ef6 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAuthentication.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAuthentication.java @@ -31,7 +31,10 @@ enum HashicorpVaultAuthentication { APPROLE("approle", "AppRole"), KUBERNETES("kubernetes", "Kubernetes"), JWT("jwt", "JWT"), - CERT("cert", "TLS certificate"); + CERT("cert", "TLS certificate"), + AWS_IAM("aws-iam", "AWS IAM"), + AZURE_MSI("azure-msi", "Azure managed identity"), + GCP_GCE("gcp-gce", "Google Compute Engine"); private final String value; private final String displayName; diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java new file mode 100644 index 0000000000000..cea626d664651 --- /dev/null +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java @@ -0,0 +1,72 @@ +/* + * 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 org.apache.camel.component.hashicorp.vault; + +import java.net.URI; +import java.util.function.Consumer; + +import org.apache.camel.util.ObjectHelper; +import org.springframework.vault.authentication.AwsIamAuthentication; +import org.springframework.vault.authentication.AwsIamAuthenticationOptions; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.client.VaultClient; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.regions.Region; + +/** + * The aws-iam login. It is in a class of its own, as it needs the AWS SDK (software.amazon.awssdk:auth), an optional + * dependency of the component: the class is loaded only for the aws-iam login. + */ +final class HashicorpVaultAwsIam { + + private HashicorpVaultAwsIam() { + } + + /** + * The aws-iam login, which signs its request with the credentials of the AWS SDK default chain: environment + * variables, system properties, web identity token (such as IAM roles for service accounts on EKS), profile, + * container (ECS) or instance profile (EC2). + * + * @param closeOnStop takes the credentials provider, to close with the client + */ + static ClientAuthentication authentication( + HashicorpVaultClientSettings settings, VaultClient loginClient, Consumer closeOnStop) { + DefaultCredentialsProvider credentials = DefaultCredentialsProvider.builder().build(); + closeOnStop.accept(credentials); + return new AwsIamAuthentication(options(settings, credentials), loginClient); + } + + static AwsIamAuthenticationOptions options(HashicorpVaultClientSettings settings, AwsCredentialsProvider credentials) { + AwsIamAuthenticationOptions.AwsIamAuthenticationOptionsBuilder builder = AwsIamAuthenticationOptions.builder() + .credentialsProvider(credentials) + .role(settings.getRole()); + if (ObjectHelper.isNotEmpty(settings.getAwsRegion())) { + builder.region(Region.of(settings.getAwsRegion())); + } + if (ObjectHelper.isNotEmpty(settings.getAwsStsEndpoint())) { + builder.endpointUri(URI.create(settings.getAwsStsEndpoint())); + } + if (ObjectHelper.isNotEmpty(settings.getAwsIamServerId())) { + builder.serverId(settings.getAwsIamServerId()); + } + if (ObjectHelper.isNotEmpty(settings.getAuthMountPath())) { + builder.path(settings.getAuthMountPath()); + } + return builder.build(); + } +} diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java index df64d16732d5a..d347acf085d1b 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java @@ -19,7 +19,14 @@ import java.io.Closeable; import java.io.IOException; import java.net.HttpURLConnection; +import java.net.Proxy; +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Consumer; import java.util.function.Supplier; import javax.net.ssl.HttpsURLConnection; @@ -29,15 +36,21 @@ import org.apache.camel.CamelContext; import org.apache.camel.spi.ExecutorServiceManager; import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; import org.springframework.vault.authentication.AppRoleAuthentication; import org.springframework.vault.authentication.AppRoleAuthenticationOptions; import org.springframework.vault.authentication.AppRoleAuthenticationOptions.RoleId; import org.springframework.vault.authentication.AppRoleAuthenticationOptions.SecretId; +import org.springframework.vault.authentication.AzureMsiAuthentication; +import org.springframework.vault.authentication.AzureMsiAuthenticationOptions; import org.springframework.vault.authentication.ClientAuthentication; import org.springframework.vault.authentication.ClientCertificateAuthentication; import org.springframework.vault.authentication.ClientCertificateAuthenticationOptions; +import org.springframework.vault.authentication.GcpComputeAuthentication; +import org.springframework.vault.authentication.GcpComputeAuthenticationOptions; import org.springframework.vault.authentication.JwtAuthentication; import org.springframework.vault.authentication.JwtAuthenticationOptions; import org.springframework.vault.authentication.KubernetesAuthentication; @@ -50,6 +63,7 @@ import org.springframework.vault.client.VaultEndpoint; import org.springframework.vault.core.VaultTemplate; import org.springframework.vault.support.ClientOptions; +import org.springframework.web.client.RestClient; /** * A client of HashiCorp Vault that logs in as its {@link HashicorpVaultClientSettings} say, and keeps its token valid: @@ -62,17 +76,30 @@ */ public final class HashicorpVaultClient implements Closeable { + private static final Logger LOG = LoggerFactory.getLogger(HashicorpVaultClient.class); + + // a class of the AWS SDK that the aws-iam login needs + private static final String AWS_SDK_CLASS = "software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider"; + // the resource of the Azure login in the documentation of HashiCorp Vault + static final String DEFAULT_AZURE_RESOURCE = "https://management.azure.com/"; + private static final String AZURE_IDENTITY_TOKEN_URI + = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01"; + private final VaultTemplate vaultTemplate; private final LifecycleAwareSessionManager sessionManager; private final ExecutorServiceManager executorServiceManager; private final ScheduledExecutorService renewal; + // what the login holds, such as the credentials provider of the AWS SDK, closed with the client + private final List resources; private HashicorpVaultClient(VaultTemplate vaultTemplate, LifecycleAwareSessionManager sessionManager, - ExecutorServiceManager executorServiceManager, ScheduledExecutorService renewal) { + ExecutorServiceManager executorServiceManager, ScheduledExecutorService renewal, + List resources) { this.vaultTemplate = vaultTemplate; this.sessionManager = sessionManager; this.executorServiceManager = executorServiceManager; this.renewal = renewal; + this.resources = resources; } /** @@ -97,7 +124,14 @@ public static HashicorpVaultClient create(CamelContext camelContext, Object sour // their path: so only the login, and the renewal and revocation of its token, are sent to the namespace String namespace = settings.getCloudNamespace(); VaultClient loginClient = namespace != null ? vaultClient(endpoint, requestFactory, namespace) : client; - ClientAuthentication authentication = createAuthentication(settings, loginClient); + List resources = new ArrayList<>(); + ClientAuthentication authentication; + try { + authentication = createAuthentication(settings, loginClient, resources::add); + } catch (RuntimeException e) { + close(resources); + throw e; + } ExecutorServiceManager executorServiceManager = camelContext.getExecutorServiceManager(); ScheduledExecutorService renewal @@ -106,10 +140,11 @@ public static HashicorpVaultClient create(CamelContext camelContext, Object sour LifecycleAwareSessionManager sessionManager = new LifecycleAwareSessionManager(authentication, new ConcurrentTaskScheduler(renewal), loginClient); return new HashicorpVaultClient( - new VaultTemplate(client, sessionManager), sessionManager, executorServiceManager, renewal); + new VaultTemplate(client, sessionManager), sessionManager, executorServiceManager, renewal, resources); } catch (RuntimeException e) { // nothing is scheduled on the executor yet, so there is nothing to wait for executorServiceManager.shutdownNow(renewal); + close(resources); throw e; } } @@ -161,10 +196,25 @@ public static void validate(HashicorpVaultClientSettings settings) { throw new IllegalArgumentException("The cert login needs the https scheme"); } } + case AWS_IAM -> { + validateRole(settings, "aws-iam"); + if (ObjectHelper.loadClass(AWS_SDK_CLASS, HashicorpVaultClient.class.getClassLoader()) == null) { + throw new IllegalArgumentException( + "The aws-iam login needs the AWS SDK: add the software.amazon.awssdk:auth dependency"); + } + } + case AZURE_MSI -> validateRole(settings, "azure-msi"); + case GCP_GCE -> validateRole(settings, "gcp-gce"); default -> throw new IllegalStateException("Unexpected login: " + settings.getAuthentication()); } } + private static void validateRole(HashicorpVaultClientSettings settings, String login) { + if (ObjectHelper.isEmpty(settings.getRole())) { + throw new IllegalArgumentException("The " + login + " login needs a role"); + } + } + private static void validateJwt(HashicorpVaultClientSettings settings, String login) { if (ObjectHelper.isNotEmpty(settings.getJwt()) && ObjectHelper.isNotEmpty(settings.getJwtFile())) { throw new IllegalArgumentException( @@ -174,14 +224,21 @@ private static void validateJwt(HashicorpVaultClientSettings settings, String lo /** * The login of the settings, which logs in with the given client. + * + * @param closeOnStop takes what the login holds, to close with the client */ - static ClientAuthentication createAuthentication(HashicorpVaultClientSettings settings, VaultClient loginClient) { + static ClientAuthentication createAuthentication( + HashicorpVaultClientSettings settings, VaultClient loginClient, Consumer closeOnStop) { return switch (HashicorpVaultAuthentication.of(settings.getAuthentication())) { case TOKEN -> new TokenAuthentication(settings.getToken()); case APPROLE -> new AppRoleAuthentication(appRoleOptions(settings), loginClient); case KUBERNETES -> new KubernetesAuthentication(kubernetesOptions(settings), loginClient); case JWT -> new JwtAuthentication(jwtOptions(settings), loginClient); case CERT -> new ClientCertificateAuthentication(certOptions(settings), loginClient); + // in a class of its own, as it needs the AWS SDK, an optional dependency + case AWS_IAM -> HashicorpVaultAwsIam.authentication(settings, loginClient, closeOnStop); + case AZURE_MSI -> new AzureMsiAuthentication(azureMsiOptions(settings), loginClient, metadataClient()); + case GCP_GCE -> new GcpComputeAuthentication(gcpComputeOptions(settings), loginClient, metadataClient()); }; } @@ -232,6 +289,46 @@ static ClientCertificateAuthenticationOptions certOptions(HashicorpVaultClientSe return builder.build(); } + static AzureMsiAuthenticationOptions azureMsiOptions(HashicorpVaultClientSettings settings) { + String resource = ObjectHelper.isNotEmpty(settings.getAzureResource()) + ? settings.getAzureResource() : DEFAULT_AZURE_RESOURCE; + // the managed identity token for the resource of the Azure login of Vault, of the user-assigned identity when set + StringBuilder tokenUri = new StringBuilder(AZURE_IDENTITY_TOKEN_URI) + .append("&resource=").append(URLEncoder.encode(resource, StandardCharsets.UTF_8)); + if (ObjectHelper.isNotEmpty(settings.getAzureClientId())) { + tokenUri.append("&client_id=").append(URLEncoder.encode(settings.getAzureClientId(), StandardCharsets.UTF_8)); + } + AzureMsiAuthenticationOptions.AzureMsiAuthenticationOptionsBuilder builder = AzureMsiAuthenticationOptions.builder() + .role(settings.getRole()) + .identityTokenServiceUri(URI.create(tokenUri.toString())); + if (ObjectHelper.isNotEmpty(settings.getAuthMountPath())) { + builder.path(settings.getAuthMountPath()); + } + return builder.build(); + } + + static GcpComputeAuthenticationOptions gcpComputeOptions(HashicorpVaultClientSettings settings) { + GcpComputeAuthenticationOptions.GcpComputeAuthenticationOptionsBuilder builder + = GcpComputeAuthenticationOptions.builder().role(settings.getRole()); + if (ObjectHelper.isNotEmpty(settings.getAuthMountPath())) { + builder.path(settings.getAuthMountPath()); + } + return builder.build(); + } + + /** + * The HTTP client of the metadata service of the cloud (Azure instance metadata, Google Compute Engine metadata), + * which is reached directly, never through a proxy, as the clouds require. + */ + private static RestClient metadataClient() { + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); + requestFactory.setProxy(Proxy.NO_PROXY); + ClientOptions options = new ClientOptions(); + requestFactory.setConnectTimeout(options.getConnectionTimeout()); + requestFactory.setReadTimeout(options.getReadTimeout()); + return RestClient.builder().requestFactory(requestFactory).build(); + } + /** * The JWT given, else the JWT in the file, read at every login, so that a token replaced in the file (such as a * projected service account token) is picked up. @@ -299,7 +396,21 @@ public void close() { try { executorServiceManager.shutdownNow(renewal); } finally { - sessionManager.destroy(); + try { + sessionManager.destroy(); + } finally { + close(resources); + } + } + } + + private static void close(List resources) { + for (AutoCloseable resource : resources) { + try { + resource.close(); + } catch (Exception e) { + LOG.debug("Error closing {} of the HashiCorp Vault login. This exception is ignored.", resource, e); + } } } } diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettings.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettings.java index 899b653b3e70e..9c95106d50ef9 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettings.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettings.java @@ -44,12 +44,18 @@ public final class HashicorpVaultClientSettings { static final String TRUST_STORE_PASSWORD_ENV = "CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD"; static final String KEY_STORE_ENV = "CAMEL_HASHICORP_VAULT_KEY_STORE"; static final String KEY_STORE_PASSWORD_ENV = "CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD"; + static final String AWS_IAM_SERVER_ID_ENV = "CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID"; + static final String AWS_REGION_ENV = "CAMEL_HASHICORP_VAULT_AWS_REGION"; + static final String AWS_STS_ENDPOINT_ENV = "CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT"; + static final String AZURE_RESOURCE_ENV = "CAMEL_HASHICORP_VAULT_AZURE_RESOURCE"; + static final String AZURE_CLIENT_ID_ENV = "CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID"; // any of these set means the settings come from the environment variables (the cloud variable alone does not) private static final List ENVIRONMENT_SETTINGS = List.of( TOKEN_ENV, HOST_ENV, PORT_ENV, SCHEME_ENV, NAMESPACE_ENV, AUTHENTICATION_ENV, ROLE_ID_ENV, SECRET_ID_ENV, ROLE_ENV, JWT_ENV, JWT_FILE_ENV, AUTH_MOUNT_PATH_ENV, TRUST_STORE_ENV, TRUST_STORE_PASSWORD_ENV, KEY_STORE_ENV, - KEY_STORE_PASSWORD_ENV); + KEY_STORE_PASSWORD_ENV, AWS_IAM_SERVER_ID_ENV, AWS_REGION_ENV, AWS_STS_ENDPOINT_ENV, AZURE_RESOURCE_ENV, + AZURE_CLIENT_ID_ENV); private String host; private String port; @@ -68,6 +74,11 @@ public final class HashicorpVaultClientSettings { private String trustStorePassword; private String keyStore; private String keyStorePassword; + private String awsIamServerId; + private String awsRegion; + private String awsStsEndpoint; + private String azureResource; + private String azureClientId; /** * The settings of the properties function and the secret refresh task: from the CAMEL_HASHICORP_VAULT_* environment @@ -100,6 +111,11 @@ static HashicorpVaultClientSettings fromEnvironmentOrConfiguration( settings.setTrustStorePassword(environment.apply(TRUST_STORE_PASSWORD_ENV)); settings.setKeyStore(environment.apply(KEY_STORE_ENV)); settings.setKeyStorePassword(environment.apply(KEY_STORE_PASSWORD_ENV)); + settings.setAwsIamServerId(environment.apply(AWS_IAM_SERVER_ID_ENV)); + settings.setAwsRegion(environment.apply(AWS_REGION_ENV)); + settings.setAwsStsEndpoint(environment.apply(AWS_STS_ENDPOINT_ENV)); + settings.setAzureResource(environment.apply(AZURE_RESOURCE_ENV)); + settings.setAzureClientId(environment.apply(AZURE_CLIENT_ID_ENV)); } else if (configuration != null) { settings.setHost(configuration.getHost()); settings.setPort(configuration.getPort()); @@ -118,6 +134,11 @@ static HashicorpVaultClientSettings fromEnvironmentOrConfiguration( settings.setTrustStorePassword(configuration.getTrustStorePassword()); settings.setKeyStore(configuration.getKeyStore()); settings.setKeyStorePassword(configuration.getKeyStorePassword()); + settings.setAwsIamServerId(configuration.getAwsIamServerId()); + settings.setAwsRegion(configuration.getAwsRegion()); + settings.setAwsStsEndpoint(configuration.getAwsStsEndpoint()); + settings.setAzureResource(configuration.getAzureResource()); + settings.setAzureClientId(configuration.getAzureClientId()); } return settings; } @@ -175,7 +196,7 @@ public String getAuthentication() { } /** - * How to log in: token (the default), approle, kubernetes, jwt or cert + * How to log in: token (the default), approle, kubernetes, jwt, cert, aws-iam, azure-msi or gcp-gce */ public void setAuthentication(String authentication) { this.authentication = authentication; @@ -268,4 +289,44 @@ public String getKeyStorePassword() { public void setKeyStorePassword(String keyStorePassword) { this.keyStorePassword = keyStorePassword; } + + public String getAwsIamServerId() { + return awsIamServerId; + } + + public void setAwsIamServerId(String awsIamServerId) { + this.awsIamServerId = awsIamServerId; + } + + public String getAwsRegion() { + return awsRegion; + } + + public void setAwsRegion(String awsRegion) { + this.awsRegion = awsRegion; + } + + public String getAwsStsEndpoint() { + return awsStsEndpoint; + } + + public void setAwsStsEndpoint(String awsStsEndpoint) { + this.awsStsEndpoint = awsStsEndpoint; + } + + public String getAzureResource() { + return azureResource; + } + + public void setAzureResource(String azureResource) { + this.azureResource = azureResource; + } + + public String getAzureClientId() { + return azureClientId; + } + + public void setAzureClientId(String azureClientId) { + this.azureClientId = azureClientId; + } } diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java index 48f8dfb5bdf10..810dc24b2559c 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java @@ -39,7 +39,7 @@ public class HashicorpVaultConfiguration implements Cloneable { private String scheme = "https"; @UriParam private String secretPath; - @UriParam(label = "security", defaultValue = "token", enums = "token,approle,kubernetes,jwt,cert") + @UriParam(label = "security", defaultValue = "token", enums = "token,approle,kubernetes,jwt,cert,aws-iam,azure-msi,gcp-gce") private String authentication = "token"; @UriParam(label = "security", security = "secret") private String token; @@ -63,6 +63,16 @@ public class HashicorpVaultConfiguration implements Cloneable { private String keyStore; @UriParam(label = "security", security = "secret") private String keyStorePassword; + @UriParam(label = "security") + private String awsIamServerId; + @UriParam(label = "security") + private String awsRegion; + @UriParam(label = "security") + private String awsStsEndpoint; + @UriParam(label = "security", defaultValue = "https://management.azure.com/") + private String azureResource = "https://management.azure.com/"; + @UriParam(label = "security") + private String azureClientId; @UriParam private boolean cloud; @UriParam @@ -95,9 +105,10 @@ public void setSecretsEngine(String secretsEngine) { /** * How to log in to HashiCorp Vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the - * service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client - * certificate of the keyStore). The token is renewed before it expires, and the endpoint logs in again when the - * token can no longer be renewed. + * service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client + * certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed + * identity) or gcp-gce (the service account of the Google Compute Engine instance). The token is renewed before it + * expires, and the endpoint logs in again when the token can no longer be renewed. */ public String getAuthentication() { return authentication; @@ -141,8 +152,9 @@ public void setSecretId(String secretId) { } /** - * The HashiCorp Vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the - * login method has a default role. + * The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The + * jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the + * certificate role that trusts the certificate. */ public String getRole() { return role; @@ -178,7 +190,7 @@ public void setJwtFile(String jwtFile) { /** * The path the login method is mounted at in HashiCorp Vault (without auth/), when it is not the default path of - * the login method: approle, kubernetes or jwt + * the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce) */ public String getAuthMountPath() { return authMountPath; @@ -215,7 +227,7 @@ public void setTrustStorePassword(String trustStorePassword) { /** * The file with the TLS client certificate and its private key, which the endpoint presents to HashiCorp Vault: for * the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the - * certificate and the PKCS#8 private key. + * certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1. */ public String getKeyStore() { return keyStore; @@ -236,6 +248,67 @@ public void setKeyStorePassword(String keyStorePassword) { this.keyStorePassword = keyStorePassword; } + /** + * The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of HashiCorp Vault + * requires one (iam_server_id_header_value) + */ + public String getAwsIamServerId() { + return awsIamServerId; + } + + public void setAwsIamServerId(String awsIamServerId) { + this.awsIamServerId = awsIamServerId; + } + + /** + * The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for + * the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION + * environment variable). + */ + public String getAwsRegion() { + return awsRegion; + } + + public void setAwsRegion(String awsRegion) { + this.awsRegion = awsRegion; + } + + /** + * The AWS STS endpoint of the aws-iam login, which the AWS login of HashiCorp Vault must accept (its sts_endpoint). + * When not set, the global endpoint https://sts.amazonaws.com/. + */ + public String getAwsStsEndpoint() { + return awsStsEndpoint; + } + + public void setAwsStsEndpoint(String awsStsEndpoint) { + this.awsStsEndpoint = awsStsEndpoint; + } + + /** + * The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the + * Azure login of HashiCorp Vault + */ + public String getAzureResource() { + return azureResource; + } + + public void setAzureResource(String azureResource) { + this.azureResource = azureResource; + } + + /** + * The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned + * managed identity. + */ + public String getAzureClientId() { + return azureClientId; + } + + public void setAzureClientId(String azureClientId) { + this.azureClientId = azureClientId; + } + /** * Hashicorp Vault instance host to be used */ diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpoint.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpoint.java index 6dbb0b8814080..b54824c9534f3 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpoint.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultEndpoint.java @@ -120,6 +120,11 @@ HashicorpVaultClientSettings clientSettings() { settings.setTrustStorePassword(configuration.getTrustStorePassword()); settings.setKeyStore(configuration.getKeyStore()); settings.setKeyStorePassword(configuration.getKeyStorePassword()); + settings.setAwsIamServerId(configuration.getAwsIamServerId()); + settings.setAwsRegion(configuration.getAwsRegion()); + settings.setAwsStsEndpoint(configuration.getAwsStsEndpoint()); + settings.setAzureResource(configuration.getAzureResource()); + settings.setAzureClientId(configuration.getAzureClientId()); return settings; } diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultPropertiesFunction.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultPropertiesFunction.java index 347317c9457aa..a9cae400383a3 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultPropertiesFunction.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultPropertiesFunction.java @@ -42,16 +42,23 @@ *
  • CAMEL_HASHICORP_VAULT_HOST
  • *
  • CAMEL_HASHICORP_VAULT_PORT
  • *
  • CAMEL_HASHICORP_VAULT_SCHEME
  • - *
  • CAMEL_HASHICORP_VAULT_AUTHENTICATION: token (the default), approle, kubernetes, jwt or cert
  • + *
  • CAMEL_HASHICORP_VAULT_AUTHENTICATION: token (the default), approle, kubernetes, jwt, cert, aws-iam, + * azure-msi or gcp-gce
  • *
  • CAMEL_HASHICORP_VAULT_TOKEN, for the token login
  • *
  • CAMEL_HASHICORP_VAULT_ROLE_ID and CAMEL_HASHICORP_VAULT_SECRET_ID, for the approle login
  • - *
  • CAMEL_HASHICORP_VAULT_ROLE, CAMEL_HASHICORP_VAULT_JWT and - * CAMEL_HASHICORP_VAULT_JWT_FILE, for the kubernetes and jwt logins
  • + *
  • CAMEL_HASHICORP_VAULT_ROLE, the Vault role to log in as, for the kubernetes, jwt, cert and cloud + * logins
  • + *
  • CAMEL_HASHICORP_VAULT_JWT and CAMEL_HASHICORP_VAULT_JWT_FILE, for the kubernetes and jwt + * logins
  • *
  • CAMEL_HASHICORP_VAULT_AUTH_MOUNT_PATH, when the login method is not at its default path
  • *
  • CAMEL_HASHICORP_VAULT_TRUST_STORE and CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD, the * certificates to trust for TLS
  • *
  • CAMEL_HASHICORP_VAULT_KEY_STORE and CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD, the TLS client * certificate, for the cert login
  • + *
  • CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID, CAMEL_HASHICORP_VAULT_AWS_REGION and + * CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT, for the aws-iam login
  • + *
  • CAMEL_HASHICORP_VAULT_AZURE_RESOURCE and CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID, for the + * azure-msi login
  • * *

    * @@ -69,6 +76,9 @@ *

  • camel.vault.hashicorp.authMountPath
  • *
  • camel.vault.hashicorp.trustStore and camel.vault.hashicorp.trustStorePassword
  • *
  • camel.vault.hashicorp.keyStore and camel.vault.hashicorp.keyStorePassword
  • + *
  • camel.vault.hashicorp.awsIamServerId, camel.vault.hashicorp.awsRegion and + * camel.vault.hashicorp.awsStsEndpoint
  • + *
  • camel.vault.hashicorp.azureResource and camel.vault.hashicorp.azureClientId
  • * *

    * diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTls.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTls.java index 78ca6e23bab1f..a1e7cbea06af8 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTls.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTls.java @@ -55,7 +55,7 @@ final class HashicorpVaultTls { private static final Pattern PEM_BLOCK = Pattern.compile( "-----BEGIN ([A-Z0-9 ]+)-----(.+?)-----END \\1-----", Pattern.DOTALL); - // the algorithms of a PKCS#8 private key that is tried in turn, as Java 17 cannot read the algorithm of the key + // the algorithms of a PKCS#8 private key that are tried in turn, as the JDK does not read the algorithm of the key private static final List KEY_ALGORITHMS = List.of("RSA", "EC", "Ed25519", "Ed448"); private HashicorpVaultTls() { @@ -105,6 +105,13 @@ private static TrustManager[] trustManagers(String file, String password) { } } else { store = KeyStore.getInstance(new File(file), toChars(password)); + if (store.size() == 0) { + // a PKCS12 trust store keeps its certificates encrypted: without the password it reads as empty + throw new GeneralSecurityException( + password == null + ? "no certificate in the trust store, which may need its trustStorePassword" + : "no certificate in the trust store"); + } } TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); factory.init(store); @@ -114,7 +121,7 @@ private static TrustManager[] trustManagers(String file, String password) { } } - private static KeyManager[] keyManagers(String file, String password) { + static KeyManager[] keyManagers(String file, String password) { try { KeyStore store; char[] keyPassword; diff --git a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettingsTest.java b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettingsTest.java index 25aac2caa4f11..01f7de1e912eb 100644 --- a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettingsTest.java +++ b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettingsTest.java @@ -23,6 +23,11 @@ import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.AUTHENTICATION_ENV; import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.AUTH_MOUNT_PATH_ENV; +import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.AWS_IAM_SERVER_ID_ENV; +import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.AWS_REGION_ENV; +import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.AWS_STS_ENDPOINT_ENV; +import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.AZURE_CLIENT_ID_ENV; +import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.AZURE_RESOURCE_ENV; import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.CLOUD_ENV; import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.HOST_ENV; import static org.apache.camel.component.hashicorp.vault.HashicorpVaultClientSettings.JWT_FILE_ENV; @@ -109,6 +114,43 @@ void takesTheTlsSettingsOfTheConfiguration() { assertEquals("key-password", settings.getKeyStorePassword()); } + @Test + void takesTheCloudSettingsOfTheEnvironmentVariables() { + Map environment = Map.of( + AWS_IAM_SERVER_ID_ENV, "vault.example.com", AWS_REGION_ENV, "eu-west-1", + AWS_STS_ENDPOINT_ENV, "https://sts.eu-west-1.amazonaws.com", AZURE_RESOURCE_ENV, "https://vault.hashicorp.com", + AZURE_CLIENT_ID_ENV, "1b2c3d4e"); + + HashicorpVaultClientSettings settings + = HashicorpVaultClientSettings.fromEnvironmentOrConfiguration(configuration(), environment::get); + + assertEquals("vault.example.com", settings.getAwsIamServerId()); + assertEquals("eu-west-1", settings.getAwsRegion()); + assertEquals("https://sts.eu-west-1.amazonaws.com", settings.getAwsStsEndpoint()); + assertEquals("https://vault.hashicorp.com", settings.getAzureResource()); + assertEquals("1b2c3d4e", settings.getAzureClientId()); + assertNull(settings.getHost()); + } + + @Test + void takesTheCloudSettingsOfTheConfiguration() { + HashicorpVaultConfiguration configuration = configuration(); + configuration.setAwsIamServerId("vault.example.com"); + configuration.setAwsRegion("eu-west-1"); + configuration.setAwsStsEndpoint("https://sts.eu-west-1.amazonaws.com"); + configuration.setAzureClientId("1b2c3d4e"); + + HashicorpVaultClientSettings settings + = HashicorpVaultClientSettings.fromEnvironmentOrConfiguration(configuration, name -> null); + + assertEquals("vault.example.com", settings.getAwsIamServerId()); + assertEquals("eu-west-1", settings.getAwsRegion()); + assertEquals("https://sts.eu-west-1.amazonaws.com", settings.getAwsStsEndpoint()); + // the default resource of the configuration + assertEquals("https://management.azure.com/", settings.getAzureResource()); + assertEquals("1b2c3d4e", settings.getAzureClientId()); + } + @Test void takesTheConfigurationWhenNoEnvironmentVariableIsSet() { Map environment = Map.of(CLOUD_ENV, "true"); diff --git a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientTest.java b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientTest.java index 6b189710b4309..92ce1cad35349 100644 --- a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientTest.java +++ b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientTest.java @@ -272,7 +272,9 @@ void validatesTheSettingsOfTheLogin() { assertInvalid("The jwt login takes a JWT or a file to read it from, not both", settings); settings = settings("ldap"); - assertInvalid("Unknown HashiCorp Vault login: ldap. Use one of: token, approle, kubernetes, jwt, cert", settings); + assertInvalid( + "Unknown HashiCorp Vault login: ldap. Use one of: token, approle, kubernetes, jwt, cert, aws-iam, azure-msi, gcp-gce", + settings); settings = approle(); settings.setHost(null); diff --git a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java new file mode 100644 index 0000000000000..eece0eff107d9 --- /dev/null +++ b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java @@ -0,0 +1,198 @@ +/* + * 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 org.apache.camel.component.hashicorp.vault; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.impl.DefaultCamelContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.vault.authentication.AzureMsiAuthenticationOptions; +import org.springframework.vault.authentication.GcpComputeAuthenticationOptions; +import org.springframework.vault.support.VaultResponse; +import tools.jackson.databind.json.JsonMapper; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * The cloud logins. The aws-iam login only signs its request, so it logs in against a fake Vault. The azure-msi and + * gcp-gce logins need the metadata service of their cloud: their options are checked instead. + */ +class HashicorpVaultCloudLoginTest { + + // the AWS SDK default chain reads the credentials and the region from these system properties first + private static final List AWS_PROPERTIES = List.of("aws.accessKeyId", "aws.secretAccessKey", "aws.region"); + + private final Map savedProperties = new HashMap<>(); + private FakeVault vault; + private CamelContext context; + private HashicorpVaultClient client; + + @BeforeEach + void startVault() throws Exception { + for (String name : AWS_PROPERTIES) { + savedProperties.put(name, System.getProperty(name)); + } + System.setProperty("aws.accessKeyId", "AKIDCAMELTEST"); + System.setProperty("aws.secretAccessKey", "camel-test-secret"); + System.setProperty("aws.region", "us-east-1"); + + vault = new FakeVault(); + vault.on("secret/data/api", request -> FakeVault.secret("pw")); + vault.on("auth/token/revoke-self", request -> FakeVault.noContent()); + context = new DefaultCamelContext(); + context.start(); + } + + @AfterEach + void stopVault() { + if (client != null) { + client.close(); + } + context.stop(); + vault.close(); + savedProperties.forEach((name, value) -> { + if (value == null) { + System.clearProperty(name); + } else { + System.setProperty(name, value); + } + }); + } + + @Test + void awsIamLogsInWithARequestSignedForTheRegionAndEndpoint() { + vault.on("auth/aws/login", request -> FakeVault.login("aws-token", 3600)); + HashicorpVaultClientSettings settings = settings("aws-iam"); + settings.setRole("camel"); + settings.setAwsRegion("eu-west-1"); + settings.setAwsStsEndpoint("https://sts.eu-west-1.amazonaws.com"); + settings.setAwsIamServerId("vault.example.com"); + client = HashicorpVaultClient.create(context, this, settings); + + assertEquals("pw", readPassword()); + + Map login = vault.requests("auth/aws/login").get(0).json(); + assertEquals("camel", login.get("role")); + assertEquals("POST", login.get("iam_http_request_method")); + assertEquals("https://sts.eu-west-1.amazonaws.com", decode(login.get("iam_request_url"))); + assertEquals("Action=GetCallerIdentity&Version=2011-06-15", decode(login.get("iam_request_body"))); + Map headers = JsonMapper.builder().build().readValue(decode(login.get("iam_request_headers")), Map.class); + assertEquals(List.of("vault.example.com"), headers.get("X-Vault-AWS-IAM-Server-ID")); + String authorization = ((List) headers.get("Authorization")).get(0).toString(); + assertTrue(authorization.contains("Credential=AKIDCAMELTEST/"), authorization); + assertTrue(authorization.contains("/eu-west-1/sts/aws4_request"), authorization); + assertEquals("aws-token", vault.requests("secret/data/api").get(0).token()); + } + + @Test + void awsIamSignsForTheGlobalEndpointAndTheRegionOfTheAwsSdkByDefault() { + vault.on("auth/my-aws/login", request -> FakeVault.login("aws-token", 3600)); + HashicorpVaultClientSettings settings = settings("aws-iam"); + settings.setRole("camel"); + settings.setAuthMountPath("my-aws"); + client = HashicorpVaultClient.create(context, this, settings); + + assertEquals("pw", readPassword()); + + Map login = vault.requests("auth/my-aws/login").get(0).json(); + assertEquals("https://sts.amazonaws.com/", decode(login.get("iam_request_url"))); + Map headers = JsonMapper.builder().build().readValue(decode(login.get("iam_request_headers")), Map.class); + assertNull(headers.get("X-Vault-AWS-IAM-Server-ID")); + String authorization = ((List) headers.get("Authorization")).get(0).toString(); + assertTrue(authorization.contains("/us-east-1/sts/aws4_request"), authorization); + } + + @Test + void azureMsiAsksForTheTokenOfTheResourceOfVault() { + HashicorpVaultClientSettings settings = settings("azure-msi"); + settings.setRole("camel"); + + AzureMsiAuthenticationOptions options = HashicorpVaultClient.azureMsiOptions(settings); + assertEquals("camel", options.getRole()); + assertEquals("azure", options.getPath()); + assertEquals(URI.create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01" + + "&resource=https%3A%2F%2Fmanagement.azure.com%2F"), + options.getIdentityTokenServiceUri()); + + settings.setAzureResource("https://vault.hashicorp.com"); + settings.setAzureClientId("1b2c3d4e"); + settings.setAuthMountPath("my-azure"); + options = HashicorpVaultClient.azureMsiOptions(settings); + assertEquals("my-azure", options.getPath()); + assertEquals(URI.create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01" + + "&resource=https%3A%2F%2Fvault.hashicorp.com&client_id=1b2c3d4e"), + options.getIdentityTokenServiceUri()); + + // the login happens at the first request: creating and closing the client does not reach the cloud + HashicorpVaultClient.create(context, this, settings).close(); + } + + @Test + void gcpGceLogsInAsTheRoleWithTheDefaultServiceAccount() { + HashicorpVaultClientSettings settings = settings("gcp-gce"); + settings.setRole("camel"); + + GcpComputeAuthenticationOptions options = HashicorpVaultClient.gcpComputeOptions(settings); + assertEquals("camel", options.getRole()); + assertEquals("gcp", options.getPath()); + assertEquals("default", options.getServiceAccount()); + + settings.setAuthMountPath("my-gcp"); + assertEquals("my-gcp", HashicorpVaultClient.gcpComputeOptions(settings).getPath()); + + HashicorpVaultClient.create(context, this, settings).close(); + } + + @Test + void theCloudLoginsNeedARole() { + for (String login : List.of("aws-iam", "azure-msi", "gcp-gce")) { + HashicorpVaultClientSettings settings = settings(login); + IllegalArgumentException e + = assertThrows(IllegalArgumentException.class, () -> HashicorpVaultClient.validate(settings)); + assertEquals("The " + login + " login needs a role", e.getMessage()); + } + } + + private HashicorpVaultClientSettings settings(String authentication) { + HashicorpVaultClientSettings settings = new HashicorpVaultClientSettings(); + settings.setHost("localhost"); + settings.setPort(String.valueOf(vault.port())); + settings.setScheme("http"); + settings.setAuthentication(authentication); + return settings; + } + + private String readPassword() { + VaultResponse response = client.getVaultTemplate().read("secret/data/api"); + return ((Map) response.getData().get("data")).get("password").toString(); + } + + private static String decode(Object base64) { + return new String(Base64.getDecoder().decode(base64.toString()), StandardCharsets.UTF_8); + } +} diff --git a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTlsTest.java b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTlsTest.java index d64db7d5dffd6..128cc8650bd6c 100644 --- a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTlsTest.java +++ b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultTlsTest.java @@ -19,7 +19,9 @@ import java.nio.file.Path; import java.util.Map; +import javax.net.ssl.KeyManager; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.X509KeyManager; import org.apache.camel.CamelContext; import org.apache.camel.component.hashicorp.vault.FakeVault.Request; @@ -40,8 +42,8 @@ *

    * The TLS material in tls/ was made with OpenSSL, valid for 100 years: a CA (ca.pem, also in the PKCS12 trust store * truststore.p12), the certificate of localhost (server.p12), and the client certificate camel-client with its RSA key - * in PKCS#8 (client.pem), in PKCS#1 (client-rsa.pem) and in PKCS12 (client.p12). The password of the PKCS12 stores is - * changeit. + * in PKCS#8 (client.pem), in PKCS#1 (client-rsa.pem) and in PKCS12 (client.p12), and a self-signed certificate with an + * EC key in PKCS#8 (client-ec.pem). The password of the PKCS12 stores is changeit. */ class HashicorpVaultTlsTest { @@ -150,6 +152,27 @@ void validatesTheSettingsOfTheCertLogin() { assertEquals("The cert login needs the https scheme", e.getMessage()); } + @Test + void readsAnEcKeyInPkcs8() { + KeyManager[] managers = HashicorpVaultTls.keyManagers(tlsFile("client-ec.pem"), null); + + X509KeyManager manager = (X509KeyManager) managers[0]; + assertEquals("EC", manager.getPrivateKey("client").getAlgorithm()); + assertEquals("CN=camel-client-ec", manager.getCertificateChain("client")[0].getSubjectX500Principal().getName()); + } + + @Test + void reportsATrustStoreThatReadsAsEmptyWithoutItsPassword() { + HashicorpVaultClientSettings settings = token(); + // the certificates of a PKCS12 trust store are encrypted + settings.setTrustStore(tlsFile("truststore.p12")); + + IllegalArgumentException e + = assertThrows(IllegalArgumentException.class, () -> HashicorpVaultClient.create(context, this, settings)); + assertTrue(e.getMessage().endsWith("no certificate in the trust store, which may need its trustStorePassword"), + e.getMessage()); + } + @Test void failsWhenAStoreCannotBeRead() { HashicorpVaultClientSettings settings = token(); diff --git a/components/camel-hashicorp-vault/src/test/resources/org/apache/camel/component/hashicorp/vault/tls/client-ec.pem b/components/camel-hashicorp-vault/src/test/resources/org/apache/camel/component/hashicorp/vault/tls/client-ec.pem new file mode 100644 index 0000000000000..9fa7f4544a6fc --- /dev/null +++ b/components/camel-hashicorp-vault/src/test/resources/org/apache/camel/component/hashicorp/vault/tls/client-ec.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIBjDCCATGgAwIBAgIUHb1cDokF4MCNzaDlRMHehmCKmCQwCgYIKoZIzj0EAwIw +GjEYMBYGA1UEAwwPY2FtZWwtY2xpZW50LWVjMCAXDTI2MTExMTE2MjExMFoYDzIx +MjYxMDE4MTYyMTEwWjAaMRgwFgYDVQQDDA9jYW1lbC1jbGllbnQtZWMwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAAS1B97ZiB5m9BPMvrNQRhIb7Lbgv/F2F3T4rZpj +h5bRsrtvsmDmyIsNpQbv1Vh3W9H+/X2QRq8MVbIjA697bIi/o1MwUTAdBgNVHQ4E +FgQUYsVewph5Ay+Of7I7auFMuQbg2icwHwYDVR0jBBgwFoAUYsVewph5Ay+Of7I7 +auFMuQbg2icwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEAh1pj +ZRZZHUyW63+81e+BD33i09DAplWb3QoO3tpj6B0CIQDMxXgG/dChhGXgLQZQwXS0 +7sgQ8nACDjMYwMrQJdEAhQ== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd+nxcwIxW2Sr5kVu +oeGvJhI6KsiAS7EHQiJl7UK6rZehRANCAAS1B97ZiB5m9BPMvrNQRhIb7Lbgv/F2 +F3T4rZpjh5bRsrtvsmDmyIsNpQbv1Vh3W9H+/X2QRq8MVbIjA697bIi/ +-----END PRIVATE KEY----- diff --git a/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java b/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java index c805cd4584b4b..01be424b4e98d 100644 --- a/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java +++ b/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java @@ -26,7 +26,7 @@ */ public class HashicorpVaultConfiguration extends VaultConfiguration { - @Metadata(defaultValue = "token", enums = "token,approle,kubernetes,jwt,cert") + @Metadata(defaultValue = "token", enums = "token,approle,kubernetes,jwt,cert,aws-iam,azure-msi,gcp-gce") private @Nullable String authentication = "token"; @Metadata(security = "secret") private @Nullable String token; @@ -50,6 +50,16 @@ public class HashicorpVaultConfiguration extends VaultConfiguration { private @Nullable String keyStore; @Metadata(security = "secret") private @Nullable String keyStorePassword; + @Metadata + private @Nullable String awsIamServerId; + @Metadata + private @Nullable String awsRegion; + @Metadata + private @Nullable String awsStsEndpoint; + @Metadata(defaultValue = "https://management.azure.com/") + private @Nullable String azureResource = "https://management.azure.com/"; + @Metadata + private @Nullable String azureClientId; @Metadata(required = true) private @Nullable String host; @Metadata(required = true) @@ -87,9 +97,10 @@ public void setToken(@Nullable String token) { /** * How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the - * service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client - * certificate of the keyStore). Camel renews the token before it expires, and logs in again when the token can no - * longer be renewed. + * service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client + * certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed + * identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before + * it expires, and logs in again when the token can no longer be renewed. * * @since 4.24 */ @@ -137,8 +148,9 @@ public void setSecretId(@Nullable String secretId) { } /** - * The hashicorp vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the - * login method has a default role. + * The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The + * jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the + * certificate role that trusts the certificate. * * @since 4.24 */ @@ -189,7 +201,7 @@ public void setJwtFile(@Nullable String jwtFile) { /** * The path the login method is mounted at in hashicorp vault (without auth/), when it is not the default path of - * the login method: approle, kubernetes or jwt + * the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce) * * @since 4.24 */ @@ -241,7 +253,7 @@ public void setTrustStorePassword(@Nullable String trustStorePassword) { /** * The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the * cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the - * certificate and the PKCS#8 private key. + * certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1. * * @since 4.24 */ @@ -265,6 +277,92 @@ public void setKeyStorePassword(@Nullable String keyStorePassword) { this.keyStorePassword = keyStorePassword; } + /** + * @since 4.24 + */ + public @Nullable String getAwsIamServerId() { + return awsIamServerId; + } + + /** + * The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault + * requires one (iam_server_id_header_value) + * + * @since 4.24 + */ + public void setAwsIamServerId(@Nullable String awsIamServerId) { + this.awsIamServerId = awsIamServerId; + } + + /** + * @since 4.24 + */ + public @Nullable String getAwsRegion() { + return awsRegion; + } + + /** + * The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for + * the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION + * environment variable). + * + * @since 4.24 + */ + public void setAwsRegion(@Nullable String awsRegion) { + this.awsRegion = awsRegion; + } + + /** + * @since 4.24 + */ + public @Nullable String getAwsStsEndpoint() { + return awsStsEndpoint; + } + + /** + * The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). + * When not set, the global endpoint https://sts.amazonaws.com/. + * + * @since 4.24 + */ + public void setAwsStsEndpoint(@Nullable String awsStsEndpoint) { + this.awsStsEndpoint = awsStsEndpoint; + } + + /** + * @since 4.24 + */ + public @Nullable String getAzureResource() { + return azureResource; + } + + /** + * The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the + * Azure login of hashicorp vault + * + * @since 4.24 + */ + public void setAzureResource(@Nullable String azureResource) { + this.azureResource = azureResource; + } + + /** + * @since 4.24 + */ + public @Nullable String getAzureClientId() { + return azureClientId; + } + + /** + * The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned + * managed identity. + * + * @since 4.24 + */ + public void setAzureClientId(@Nullable String azureClientId) { + this.azureClientId = azureClientId; + } + public @Nullable String getHost() { return host; } diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationConfigurer.java index 1b6963f0e4dc1..312d56a493186 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationConfigurer.java @@ -27,8 +27,18 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "authmountpath": case "authMountPath": target.setAuthMountPath(property(camelContext, java.lang.String.class, value)); return true; case "authentication": target.setAuthentication(property(camelContext, java.lang.String.class, value)); return true; + case "awsiamserverid": + case "awsIamServerId": target.setAwsIamServerId(property(camelContext, java.lang.String.class, value)); return true; + case "awsregion": + case "awsRegion": target.setAwsRegion(property(camelContext, java.lang.String.class, value)); return true; + case "awsstsendpoint": + case "awsStsEndpoint": target.setAwsStsEndpoint(property(camelContext, java.lang.String.class, value)); return true; case "awsvaultconfiguration": case "awsVaultConfiguration": target.setAwsVaultConfiguration(property(camelContext, org.apache.camel.vault.AwsVaultConfiguration.class, value)); return true; + case "azureclientid": + case "azureClientId": target.setAzureClientId(property(camelContext, java.lang.String.class, value)); return true; + case "azureresource": + case "azureResource": target.setAzureResource(property(camelContext, java.lang.String.class, value)); return true; case "azurevaultconfiguration": case "azureVaultConfiguration": target.setAzureVaultConfiguration(property(camelContext, org.apache.camel.vault.AzureVaultConfiguration.class, value)); return true; case "cloud": target.setCloud(property(camelContext, boolean.class, value)); return true; @@ -82,8 +92,18 @@ public Class getOptionType(String name, boolean ignoreCase) { case "authmountpath": case "authMountPath": return java.lang.String.class; case "authentication": return java.lang.String.class; + case "awsiamserverid": + case "awsIamServerId": return java.lang.String.class; + case "awsregion": + case "awsRegion": return java.lang.String.class; + case "awsstsendpoint": + case "awsStsEndpoint": return java.lang.String.class; case "awsvaultconfiguration": case "awsVaultConfiguration": return org.apache.camel.vault.AwsVaultConfiguration.class; + case "azureclientid": + case "azureClientId": return java.lang.String.class; + case "azureresource": + case "azureResource": return java.lang.String.class; case "azurevaultconfiguration": case "azureVaultConfiguration": return org.apache.camel.vault.AzureVaultConfiguration.class; case "cloud": return boolean.class; @@ -138,8 +158,18 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "authmountpath": case "authMountPath": return target.getAuthMountPath(); case "authentication": return target.getAuthentication(); + case "awsiamserverid": + case "awsIamServerId": return target.getAwsIamServerId(); + case "awsregion": + case "awsRegion": return target.getAwsRegion(); + case "awsstsendpoint": + case "awsStsEndpoint": return target.getAwsStsEndpoint(); case "awsvaultconfiguration": case "awsVaultConfiguration": return target.getAwsVaultConfiguration(); + case "azureclientid": + case "azureClientId": return target.getAzureClientId(); + case "azureresource": + case "azureResource": return target.getAzureResource(); case "azurevaultconfiguration": case "azureVaultConfiguration": return target.getAzureVaultConfiguration(); case "cloud": return target.isCloud(); diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationPropertiesConfigurer.java index 5f62afac7fcff..cc3c175c2ae6c 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/HashicorpVaultConfigurationPropertiesConfigurer.java @@ -25,7 +25,12 @@ public class HashicorpVaultConfigurationPropertiesConfigurer extends org.apache. Map map = new CaseInsensitiveMap(); map.put("AuthMountPath", java.lang.String.class); map.put("Authentication", java.lang.String.class); + map.put("AwsIamServerId", java.lang.String.class); + map.put("AwsRegion", java.lang.String.class); + map.put("AwsStsEndpoint", java.lang.String.class); map.put("AwsVaultConfiguration", org.apache.camel.vault.AwsVaultConfiguration.class); + map.put("AzureClientId", java.lang.String.class); + map.put("AzureResource", java.lang.String.class); map.put("AzureVaultConfiguration", org.apache.camel.vault.AzureVaultConfiguration.class); map.put("Cloud", boolean.class); map.put("CyberArkVaultConfiguration", org.apache.camel.vault.CyberArkVaultConfiguration.class); @@ -62,8 +67,18 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "authmountpath": case "authMountPath": target.setAuthMountPath(property(camelContext, java.lang.String.class, value)); return true; case "authentication": target.setAuthentication(property(camelContext, java.lang.String.class, value)); return true; + case "awsiamserverid": + case "awsIamServerId": target.setAwsIamServerId(property(camelContext, java.lang.String.class, value)); return true; + case "awsregion": + case "awsRegion": target.setAwsRegion(property(camelContext, java.lang.String.class, value)); return true; + case "awsstsendpoint": + case "awsStsEndpoint": target.setAwsStsEndpoint(property(camelContext, java.lang.String.class, value)); return true; case "awsvaultconfiguration": case "awsVaultConfiguration": target.setAwsVaultConfiguration(property(camelContext, org.apache.camel.vault.AwsVaultConfiguration.class, value)); return true; + case "azureclientid": + case "azureClientId": target.setAzureClientId(property(camelContext, java.lang.String.class, value)); return true; + case "azureresource": + case "azureResource": target.setAzureResource(property(camelContext, java.lang.String.class, value)); return true; case "azurevaultconfiguration": case "azureVaultConfiguration": target.setAzureVaultConfiguration(property(camelContext, org.apache.camel.vault.AzureVaultConfiguration.class, value)); return true; case "cloud": target.setCloud(property(camelContext, boolean.class, value)); return true; @@ -122,8 +137,18 @@ public Class getOptionType(String name, boolean ignoreCase) { case "authmountpath": case "authMountPath": return java.lang.String.class; case "authentication": return java.lang.String.class; + case "awsiamserverid": + case "awsIamServerId": return java.lang.String.class; + case "awsregion": + case "awsRegion": return java.lang.String.class; + case "awsstsendpoint": + case "awsStsEndpoint": return java.lang.String.class; case "awsvaultconfiguration": case "awsVaultConfiguration": return org.apache.camel.vault.AwsVaultConfiguration.class; + case "azureclientid": + case "azureClientId": return java.lang.String.class; + case "azureresource": + case "azureResource": return java.lang.String.class; case "azurevaultconfiguration": case "azureVaultConfiguration": return org.apache.camel.vault.AzureVaultConfiguration.class; case "cloud": return boolean.class; @@ -178,8 +203,18 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "authmountpath": case "authMountPath": return target.getAuthMountPath(); case "authentication": return target.getAuthentication(); + case "awsiamserverid": + case "awsIamServerId": return target.getAwsIamServerId(); + case "awsregion": + case "awsRegion": return target.getAwsRegion(); + case "awsstsendpoint": + case "awsStsEndpoint": return target.getAwsStsEndpoint(); case "awsvaultconfiguration": case "awsVaultConfiguration": return target.getAwsVaultConfiguration(); + case "azureclientid": + case "azureClientId": return target.getAzureClientId(); + case "azureresource": + case "azureResource": return target.getAzureResource(); case "azurevaultconfiguration": case "azureVaultConfiguration": return target.getAzureVaultConfiguration(); case "cloud": return target.isCloud(); diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index 1b2d7a784d632..92da963c36b85 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -591,19 +591,24 @@ { "name": "camel.vault.gcp.serviceAccountKey", "required": false, "description": "The Service Account Key location", "sourceType": "org.apache.camel.vault.GcpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.gcp.subscriptionName", "required": false, "description": "Define the Google Pubsub subscription Name to be used when checking for updates", "sourceType": "org.apache.camel.vault.GcpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.gcp.useDefaultInstance", "required": false, "description": "Define if we want to use the GCP Client Default Instance or not", "sourceType": "org.apache.camel.vault.GcpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, - { "name": "camel.vault.hashicorp.authentication", "required": false, "description": "How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client certificate of the keyStore). Camel renews the token before it expires, and logs in again when the token can no longer be renewed.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "enum", "javaType": "java.lang.String", "defaultValue": "token", "secret": false, "enum": [ "token", "approle", "kubernetes", "jwt", "cert" ] }, - { "name": "camel.vault.hashicorp.authMountPath", "required": false, "description": "The path the login method is mounted at in hashicorp vault (without auth\/), when it is not the default path of the login method: approle, kubernetes or jwt", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.authentication", "required": false, "description": "How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "enum", "javaType": "java.lang.String", "defaultValue": "token", "secret": false, "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ] }, + { "name": "camel.vault.hashicorp.authMountPath", "required": false, "description": "The path the login method is mounted at in hashicorp vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsIamServerId", "required": false, "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsRegion", "required": false, "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable).", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsStsEndpoint", "required": false, "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.azureClientId", "required": false, "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.azureResource", "required": false, "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "defaultValue": "https:\/\/management.azure.com\/", "secret": false }, { "name": "camel.vault.hashicorp.cloud", "required": false, "description": "Determine if the Hashicorp Vault is deployed on Hashicorp Cloud or not", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.vault.hashicorp.host", "required": true, "description": "Host to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.jwt", "required": false, "description": "The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.jwtFile", "required": false, "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, - { "name": "camel.vault.hashicorp.keyStore", "required": false, "description": "The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and the PKCS#8 private key.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.keyStore", "required": false, "description": "The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.keyStorePassword", "required": false, "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.namespace", "required": false, "description": "If the Hashicorp Vault instance is deployed on Hashicorp Cloud, this field will determine the namespace", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.port", "required": true, "description": "Port to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.refreshEnabled", "required": false, "description": "Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.vault.hashicorp.refreshPeriod", "required": false, "description": "The period (millis) between checking Hashicorp Vault for updated secrets.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "integer", "javaType": "long", "defaultValue": 60000, "secret": false }, - { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the login method has a default role.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.roleId", "required": false, "description": "The role ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.scheme", "required": true, "description": "Scheme to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.secretId", "required": false, "description": "The secret ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index ebbbbfb72fe8c..5c0ec3dc0f216 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -542,24 +542,29 @@ The camel.vault.kubernetescm supports 2 options, which are listed below. === Camel Hashicorp Vault configurations -The camel.vault.hashicorp supports 20 options, which are listed below. +The camel.vault.hashicorp supports 25 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== | Name | Description | Default | Type -| `camel.vault.hashicorp.authentication` | How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token) or cert (the TLS client certificate of the keyStore). Camel renews the token before it expires, and logs in again when the token can no longer be renewed. | token | String -| `camel.vault.hashicorp.authMountPath` | The path the login method is mounted at in hashicorp vault (without auth/), when it is not the default path of the login method: approle, kubernetes or jwt | | String +| `camel.vault.hashicorp.authentication` | How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed. | token | String +| `camel.vault.hashicorp.authMountPath` | The path the login method is mounted at in hashicorp vault (without auth/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce) | | String +| `camel.vault.hashicorp.awsIamServerId` | The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value) | | String +| `camel.vault.hashicorp.awsRegion` | The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable). | | String +| `camel.vault.hashicorp.awsStsEndpoint` | The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint \https://sts.amazonaws.com/. | | String +| `camel.vault.hashicorp.azureClientId` | The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity. | | String +| `camel.vault.hashicorp.azureResource` | The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault | https://management.azure.com/ | String | `camel.vault.hashicorp.cloud` | Determine if the Hashicorp Vault is deployed on Hashicorp Cloud or not | false | boolean | `camel.vault.hashicorp.host` | Host to access hashicorp vault | | String | `camel.vault.hashicorp.jwt` | The JWT to log in with, for the jwt and kubernetes logins. For a JWT that is replaced over time, such as a projected service account token, use jwtFile instead. | | String | `camel.vault.hashicorp.jwtFile` | The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads /var/run/secrets/kubernetes.io/serviceaccount/token when neither jwt nor jwtFile is set. | | String -| `camel.vault.hashicorp.keyStore` | The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and the PKCS#8 private key. | | String +| `camel.vault.hashicorp.keyStore` | The file with the TLS client certificate and its private key, which Camel presents to hashicorp vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1. | | String | `camel.vault.hashicorp.keyStorePassword` | The password of the key store and of its private key, when it is a PKCS12 or JKS key store | | String | `camel.vault.hashicorp.namespace` | If the Hashicorp Vault instance is deployed on Hashicorp Cloud, this field will determine the namespace | | String | `camel.vault.hashicorp.port` | Port to access hashicorp vault | | String | `camel.vault.hashicorp.refreshEnabled` | Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault. | false | boolean | `camel.vault.hashicorp.refreshPeriod` | The period (millis) between checking Hashicorp Vault for updated secrets. | 60000 | long -| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes and jwt logins. The jwt login can leave it out when the login method has a default role. | | String +| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate. | | String | `camel.vault.hashicorp.roleId` | The role ID of the AppRole, for the approle login | | String | `camel.vault.hashicorp.scheme` | Scheme to access hashicorp vault | | String | `camel.vault.hashicorp.secretId` | The secret ID of the AppRole, for the approle login | | String diff --git a/core/camel-main/src/main/java/org/apache/camel/main/HashicorpVaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/HashicorpVaultConfigurationProperties.java index a4a408f36e48e..75c0bd2c3b831 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/HashicorpVaultConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/HashicorpVaultConfigurationProperties.java @@ -58,7 +58,7 @@ public HashicorpVaultConfigurationProperties withToken(String token) { } /** - * How to log in to Hashicorp Vault: token, approle, kubernetes, jwt or cert + * How to log in to Hashicorp Vault: token, approle, kubernetes, jwt, cert, aws-iam, azure-msi or gcp-gce */ public HashicorpVaultConfigurationProperties withAuthentication(String authentication) { setAuthentication(authentication); @@ -82,7 +82,7 @@ public HashicorpVaultConfigurationProperties withSecretId(String secretId) { } /** - * The Hashicorp Vault role to log in as, for the kubernetes and jwt logins + * The Hashicorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins */ public HashicorpVaultConfigurationProperties withRole(String role) { setRole(role); @@ -146,6 +146,46 @@ public HashicorpVaultConfigurationProperties withKeyStorePassword(String keyStor return this; } + /** + * The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login + */ + public HashicorpVaultConfigurationProperties withAwsIamServerId(String awsIamServerId) { + setAwsIamServerId(awsIamServerId); + return this; + } + + /** + * The AWS region the aws-iam login signs its request for + */ + public HashicorpVaultConfigurationProperties withAwsRegion(String awsRegion) { + setAwsRegion(awsRegion); + return this; + } + + /** + * The AWS STS endpoint of the aws-iam login + */ + public HashicorpVaultConfigurationProperties withAwsStsEndpoint(String awsStsEndpoint) { + setAwsStsEndpoint(awsStsEndpoint); + return this; + } + + /** + * The resource (audience) of the managed identity token of the azure-msi login + */ + public HashicorpVaultConfigurationProperties withAzureResource(String azureResource) { + setAzureResource(azureResource); + return this; + } + + /** + * The client ID of a user-assigned managed identity, for the azure-msi login + */ + public HashicorpVaultConfigurationProperties withAzureClientId(String azureClientId) { + setAzureClientId(azureClientId); + return this; + } + /** * The Hashicorp Vault host */ diff --git a/docs/user-manual/modules/ROOT/pages/security.adoc b/docs/user-manual/modules/ROOT/pages/security.adoc index 7a936aa388707..a046393e4736e 100644 --- a/docs/user-manual/modules/ROOT/pages/security.adoc +++ b/docs/user-manual/modules/ROOT/pages/security.adoc @@ -391,7 +391,8 @@ camel.vault.hashicorp.namespace = namespace ---- Instead of a token, Camel can log in with an AppRole, with the service account of a Kubernetes pod, with a JWT, such -as a workload identity token, or with a TLS client certificate, which `camel.vault.hashicorp.authentication` chooses. +as a workload identity token, with a TLS client certificate, or with the identity of the application on AWS, Azure or +Google Compute Engine, which `camel.vault.hashicorp.authentication` chooses. For a Vault whose certificate is signed by a private CA, `camel.vault.hashicorp.trustStore` sets the certificates to trust. For example: diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java index 7f255d26011b5..82c9ff8f6e10c 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java @@ -212,10 +212,12 @@ default HashicorpVaultEndpointBuilder vaultTemplate(String vaultTemplate) { /** * How to log in to HashiCorp Vault: token (a fixed token), approle (a * role ID and a secret ID), kubernetes (the service account token of - * the pod), jwt (a JWT, such as a workload identity token) or cert (the - * TLS client certificate of the keyStore). The token is renewed before - * it expires, and the endpoint logs in again when the token can no - * longer be renewed. + * the pod), jwt (a JWT, such as a workload identity token), cert (the + * TLS client certificate of the keyStore), aws-iam (the AWS credentials + * of the application), azure-msi (the Azure managed identity) or + * gcp-gce (the service account of the Google Compute Engine instance). + * The token is renewed before it expires, and the endpoint logs in + * again when the token can no longer be renewed. * * The option is a: java.lang.String type. * @@ -232,7 +234,8 @@ default HashicorpVaultEndpointBuilder authentication(String authentication) { /** * The path the login method is mounted at in HashiCorp Vault (without * auth/), when it is not the default path of the login method: approle, - * kubernetes or jwt. + * kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or + * gcp (for gcp-gce). * * The option is a: java.lang.String type. * @@ -245,6 +248,87 @@ default HashicorpVaultEndpointBuilder authMountPath(String authMountPath) { doSetProperty("authMountPath", authMountPath); return this; } + /** + * The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam + * login, when the AWS login of HashiCorp Vault requires one + * (iam_server_id_header_value). + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param awsIamServerId the value to set + * @return the dsl builder + */ + default HashicorpVaultEndpointBuilder awsIamServerId(String awsIamServerId) { + doSetProperty("awsIamServerId", awsIamServerId); + return this; + } + /** + * The AWS region the aws-iam login signs its request for, which must be + * the region of awsStsEndpoint: us-east-1 for the global endpoint. When + * not set, the region of the AWS SDK default region chain (such as the + * AWS_REGION environment variable). + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param awsRegion the value to set + * @return the dsl builder + */ + default HashicorpVaultEndpointBuilder awsRegion(String awsRegion) { + doSetProperty("awsRegion", awsRegion); + return this; + } + /** + * The AWS STS endpoint of the aws-iam login, which the AWS login of + * HashiCorp Vault must accept (its sts_endpoint). When not set, the + * global endpoint https://sts.amazonaws.com/. + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param awsStsEndpoint the value to set + * @return the dsl builder + */ + default HashicorpVaultEndpointBuilder awsStsEndpoint(String awsStsEndpoint) { + doSetProperty("awsStsEndpoint", awsStsEndpoint); + return this; + } + /** + * The client ID of a user-assigned managed identity, for the azure-msi + * login. When not set, the system-assigned managed identity. + * + * The option is a: java.lang.String type. + * + * Group: security + * + * @param azureClientId the value to set + * @return the dsl builder + */ + default HashicorpVaultEndpointBuilder azureClientId(String azureClientId) { + doSetProperty("azureClientId", azureClientId); + return this; + } + /** + * The resource (audience) of the managed identity token of the + * azure-msi login, which must be the resource of the Azure login of + * HashiCorp Vault. + * + * The option is a: java.lang.String type. + * + * Default: https://management.azure.com/ + * Group: security + * + * @param azureResource the value to set + * @return the dsl builder + */ + default HashicorpVaultEndpointBuilder azureResource(String azureResource) { + doSetProperty("azureResource", azureResource); + return this; + } /** * The JWT to log in with, for the jwt and kubernetes logins. For a JWT * that is replaced over time, such as a projected service account @@ -282,7 +366,8 @@ default HashicorpVaultEndpointBuilder jwtFile(String jwtFile) { * The file with the TLS client certificate and its private key, which * the endpoint presents to HashiCorp Vault: for the cert login, or for * a Vault that requires client certificates. A PKCS12 or JKS key store, - * or PEM with the certificate and the PKCS#8 private key. + * or PEM with the certificate and its unencrypted private key, in + * PKCS#8 or, for an RSA key, in PKCS#1. * * The option is a: java.lang.String type. * @@ -311,9 +396,10 @@ default HashicorpVaultEndpointBuilder keyStorePassword(String keyStorePassword) return this; } /** - * The HashiCorp Vault role to log in as, for the kubernetes and jwt - * logins. The jwt login can leave it out when the login method has a - * default role. + * The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, + * aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out + * when the login method has a default role, and the cert login to let + * Vault pick the certificate role that trusts the certificate. * * The option is a: java.lang.String type. * From f177c76b0e553da43096d7359d6aa204858b95cf Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Thu, 12 Nov 2026 15:00:40 +0100 Subject: [PATCH 2/2] CAMEL-25675: camel-hashicorp-vault - address review feedback on the aws-iam login Without awsRegion and awsStsEndpoint, the aws-iam login signs its request for us-east-1, which the global STS endpoint needs, as vault login -method=aws does. The role is optional for aws-iam: Vault then takes the role named as the IAM principal. A web identity token (such as IRSA on EKS) needs the sts module of the AWS SDK, without which the SDK falls through to other credentials: the docs say so, and the validation fails when AWS_WEB_IDENTITY_TOKEN_FILE is set and the sts module is missing. The Cloud logins section has an aws-iam example; the kubernetes validation uses validateRole. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Andrea Cosentino --- .../catalog/components/hashicorp-vault.json | 4 +- .../docs/hashicorp-vault-component.adoc | 51 ++++++++++++----- .../org/apache/camel/catalog/docs/main.adoc | 4 +- .../camel-main-configuration-metadata.json | 4 +- .../hashicorp/vault/hashicorp-vault.json | 4 +- .../main/docs/hashicorp-vault-component.adoc | 51 ++++++++++++----- .../hashicorp/vault/HashicorpVaultAwsIam.java | 37 ++++++++++-- .../hashicorp/vault/HashicorpVaultClient.java | 7 +-- .../vault/HashicorpVaultConfiguration.java | 9 +-- .../vault/HashicorpVaultCloudLoginTest.java | 57 +++++++++++++++++-- .../vault/HashicorpVaultConfiguration.java | 9 +-- .../camel-main-configuration-metadata.json | 4 +- core/camel-main/src/main/docs/main.adoc | 4 +- .../HashicorpVaultEndpointBuilderFactory.java | 9 +-- 14 files changed, 190 insertions(+), 64 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json index 58915e6abd535..6e6a8a0f0d77f 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hashicorp-vault.json @@ -51,7 +51,7 @@ "authentication": { "index": 10, "kind": "parameter", "displayName": "Authentication", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "token", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "How to log in to HashiCorp Vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). The token is renewed before it expires, and the endpoint logs in again when the token can no longer be renewed." }, "authMountPath": { "index": 11, "kind": "parameter", "displayName": "Auth Mount Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The path the login method is mounted at in HashiCorp Vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)" }, "awsIamServerId": { "index": 12, "kind": "parameter", "displayName": "Aws Iam Server Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of HashiCorp Vault requires one (iam_server_id_header_value)" }, - "awsRegion": { "index": 13, "kind": "parameter", "displayName": "Aws Region", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable)." }, + "awsRegion": { "index": 13, "kind": "parameter", "displayName": "Aws Region", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION environment variable)." }, "awsStsEndpoint": { "index": 14, "kind": "parameter", "displayName": "Aws Sts Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of HashiCorp Vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/." }, "azureClientId": { "index": 15, "kind": "parameter", "displayName": "Azure Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity." }, "azureResource": { "index": 16, "kind": "parameter", "displayName": "Azure Resource", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "https:\/\/management.azure.com\/", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of HashiCorp Vault" }, @@ -59,7 +59,7 @@ "jwtFile": { "index": 18, "kind": "parameter", "displayName": "Jwt File", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set." }, "keyStore": { "index": 19, "kind": "parameter", "displayName": "Key Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the TLS client certificate and its private key, which the endpoint presents to HashiCorp Vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1." }, "keyStorePassword": { "index": 20, "kind": "parameter", "displayName": "Key Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store" }, - "role": { "index": 21, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate." }, + "role": { "index": 21, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the certificate." }, "roleId": { "index": 22, "kind": "parameter", "displayName": "Role Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The role ID of the AppRole, for the approle login" }, "secretId": { "index": 23, "kind": "parameter", "displayName": "Secret Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The secret ID of the AppRole, for the approle login" }, "token": { "index": 24, "kind": "parameter", "displayName": "Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Token to be used, for the token login" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc index 00b6bfb15a7e0..57e51b1837219 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hashicorp-vault-component.adoc @@ -80,7 +80,8 @@ JWT login of Vault has a default role. it, Vault tries every certificate role that trusts the certificate. The login needs the `https` scheme. | `aws-iam` -| `role`: the Vault role of the application, which logs in with its AWS credentials, see <>. +| `role`: the Vault role of the application, which logs in with its AWS credentials, see <>. Without +`role`, Vault takes the role named as the IAM principal of the application. | `azure-msi` | `role`: the Vault role of the application, which logs in with its Azure managed identity, see <>. @@ -146,11 +147,33 @@ The `aws-iam` login signs a request to AWS STS with the credentials of the AWS S variables, the system properties, a web identity token (such as IAM roles for service accounts on Amazon EKS), the profile, the container credentials (Amazon ECS) or the instance profile (Amazon EC2). Vault checks the request with STS. The login needs the AWS SDK: add the `software.amazon.awssdk:auth` dependency, in the version of the AWS SDK of -the Camel AWS components. The request is sent to `awsStsEndpoint`, by default the global endpoint -`https://sts.amazonaws.com/`, and signed for `awsRegion`, by default the region of the AWS SDK default region chain -(such as the `AWS_REGION` environment variable). The global endpoint takes requests signed for `us-east-1`; to use a -regional endpoint, set it with its region, as the AWS login of Vault is configured (`sts_endpoint` and `sts_region`). -`awsIamServerId` sets the `X-Vault-AWS-IAM-Server-ID` header, when the AWS login of Vault requires one. +the Camel AWS components. A web identity token also needs the `software.amazon.awssdk:sts` dependency, and an SSO +profile the `software.amazon.awssdk:sso` and `software.amazon.awssdk:ssooidc` dependencies. Without the `sts` +module, the AWS SDK skips the web identity token and takes the next credentials of the chain, such as those of the +instance: so Camel refuses to start the login when a web identity token is set (`AWS_WEB_IDENTITY_TOKEN_FILE`) and +the `sts` module is missing. + +The request is sent to `awsStsEndpoint`, by default the global endpoint `https://sts.amazonaws.com/`, which takes +requests signed for `us-east-1`. Without `awsStsEndpoint` and `awsRegion`, the request is signed for `us-east-1`, +whatever the region of the application, as `vault login -method=aws` does. To use a regional endpoint, set +`awsStsEndpoint` and its region in `awsRegion`, as the AWS login of Vault is configured (`sts_endpoint` and +`sts_region`); without `awsRegion`, the request is then signed for the region of the AWS SDK default region chain, +such as the `AWS_REGION` environment variable. `awsIamServerId` sets the `X-Vault-AWS-IAM-Server-ID` header, when the +AWS login of Vault requires one. + +For example, the properties function logs in with the AWS credentials of the application, through the STS endpoint +of its region: + +[source,properties] +---- +camel.vault.hashicorp.host = vault.example.com +camel.vault.hashicorp.port = 8200 +camel.vault.hashicorp.scheme = https +camel.vault.hashicorp.authentication = aws-iam +camel.vault.hashicorp.role = my-application +camel.vault.hashicorp.awsStsEndpoint = https://sts.eu-west-1.amazonaws.com +camel.vault.hashicorp.awsRegion = eu-west-1 +---- The `azure-msi` login asks the Azure instance metadata service (`169.254.169.254`) for a token of the managed identity of the virtual machine, for the resource `azureResource`, by default `https://management.azure.com/`, which must be @@ -453,14 +476,14 @@ camel.vault.hashicorp.authentication = kubernetes camel.vault.hashicorp.role = my-application ---- -The properties function also reads these options from the environment variables -`CAMEL_HASHICORP_VAULT_AUTHENTICATION`, `CAMEL_HASHICORP_VAULT_ROLE_ID`, `CAMEL_HASHICORP_VAULT_SECRET_ID`, -`CAMEL_HASHICORP_VAULT_ROLE`, `CAMEL_HASHICORP_VAULT_JWT`, `CAMEL_HASHICORP_VAULT_JWT_FILE` and -`CAMEL_HASHICORP_VAULT_AUTH_MOUNT_PATH`, and the settings of <> from `CAMEL_HASHICORP_VAULT_TRUST_STORE`, -`CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD`, `CAMEL_HASHICORP_VAULT_KEY_STORE` and -`CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`, and the settings of the <> from -`CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID`, `CAMEL_HASHICORP_VAULT_AWS_REGION`, `CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT`, -`CAMEL_HASHICORP_VAULT_AZURE_RESOURCE` and `CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the +The properties function also reads these options from the environment variables `CAMEL_HASHICORP_VAULT_AUTHENTICATION`, +`CAMEL_HASHICORP_VAULT_ROLE_ID`, `CAMEL_HASHICORP_VAULT_SECRET_ID`, `CAMEL_HASHICORP_VAULT_ROLE`, +`CAMEL_HASHICORP_VAULT_JWT`, `CAMEL_HASHICORP_VAULT_JWT_FILE` and `CAMEL_HASHICORP_VAULT_AUTH_MOUNT_PATH`, and the +settings of <> from `CAMEL_HASHICORP_VAULT_TRUST_STORE`, `CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD`, +`CAMEL_HASHICORP_VAULT_KEY_STORE` and `CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`, and the settings of the <> from `CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID`, `CAMEL_HASHICORP_VAULT_AWS_REGION`, +`CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT`, `CAMEL_HASHICORP_VAULT_AZURE_RESOURCE` and +`CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the properties function takes all its settings from the environment variables, and none from the `camel.vault.hashicorp` configuration. The secret refresh task logs in the same way as the properties function. diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc index 5c0ec3dc0f216..80c685a6c5808 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc @@ -550,7 +550,7 @@ The camel.vault.hashicorp supports 25 options, which are listed below. | `camel.vault.hashicorp.authentication` | How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed. | token | String | `camel.vault.hashicorp.authMountPath` | The path the login method is mounted at in hashicorp vault (without auth/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce) | | String | `camel.vault.hashicorp.awsIamServerId` | The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value) | | String -| `camel.vault.hashicorp.awsRegion` | The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable). | | String +| `camel.vault.hashicorp.awsRegion` | The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION environment variable). | | String | `camel.vault.hashicorp.awsStsEndpoint` | The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint \https://sts.amazonaws.com/. | | String | `camel.vault.hashicorp.azureClientId` | The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity. | | String | `camel.vault.hashicorp.azureResource` | The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault | https://management.azure.com/ | String @@ -564,7 +564,7 @@ The camel.vault.hashicorp supports 25 options, which are listed below. | `camel.vault.hashicorp.port` | Port to access hashicorp vault | | String | `camel.vault.hashicorp.refreshEnabled` | Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault. | false | boolean | `camel.vault.hashicorp.refreshPeriod` | The period (millis) between checking Hashicorp Vault for updated secrets. | 60000 | long -| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate. | | String +| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the certificate. | | String | `camel.vault.hashicorp.roleId` | The role ID of the AppRole, for the approle login | | String | `camel.vault.hashicorp.scheme` | Scheme to access hashicorp vault | | String | `camel.vault.hashicorp.secretId` | The secret ID of the AppRole, for the approle login | | String diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json index 92da963c36b85..0db48e268c8d8 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json @@ -594,7 +594,7 @@ { "name": "camel.vault.hashicorp.authentication", "required": false, "description": "How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "enum", "javaType": "java.lang.String", "defaultValue": "token", "secret": false, "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ] }, { "name": "camel.vault.hashicorp.authMountPath", "required": false, "description": "The path the login method is mounted at in hashicorp vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.awsIamServerId", "required": false, "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, - { "name": "camel.vault.hashicorp.awsRegion", "required": false, "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable).", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsRegion", "required": false, "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION environment variable).", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.awsStsEndpoint", "required": false, "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.azureClientId", "required": false, "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.azureResource", "required": false, "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "defaultValue": "https:\/\/management.azure.com\/", "secret": false }, @@ -608,7 +608,7 @@ { "name": "camel.vault.hashicorp.port", "required": true, "description": "Port to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.refreshEnabled", "required": false, "description": "Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.vault.hashicorp.refreshPeriod", "required": false, "description": "The period (millis) between checking Hashicorp Vault for updated secrets.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "integer", "javaType": "long", "defaultValue": 60000, "secret": false }, - { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the certificate.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.roleId", "required": false, "description": "The role ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.scheme", "required": true, "description": "Scheme to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.secretId", "required": false, "description": "The secret ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, diff --git a/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json b/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json index 58915e6abd535..6e6a8a0f0d77f 100644 --- a/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json +++ b/components/camel-hashicorp-vault/src/generated/resources/META-INF/org/apache/camel/component/hashicorp/vault/hashicorp-vault.json @@ -51,7 +51,7 @@ "authentication": { "index": 10, "kind": "parameter", "displayName": "Authentication", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "token", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "How to log in to HashiCorp Vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). The token is renewed before it expires, and the endpoint logs in again when the token can no longer be renewed." }, "authMountPath": { "index": 11, "kind": "parameter", "displayName": "Auth Mount Path", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The path the login method is mounted at in HashiCorp Vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)" }, "awsIamServerId": { "index": 12, "kind": "parameter", "displayName": "Aws Iam Server Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of HashiCorp Vault requires one (iam_server_id_header_value)" }, - "awsRegion": { "index": 13, "kind": "parameter", "displayName": "Aws Region", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable)." }, + "awsRegion": { "index": 13, "kind": "parameter", "displayName": "Aws Region", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION environment variable)." }, "awsStsEndpoint": { "index": 14, "kind": "parameter", "displayName": "Aws Sts Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of HashiCorp Vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/." }, "azureClientId": { "index": 15, "kind": "parameter", "displayName": "Azure Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity." }, "azureResource": { "index": 16, "kind": "parameter", "displayName": "Azure Resource", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "https:\/\/management.azure.com\/", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of HashiCorp Vault" }, @@ -59,7 +59,7 @@ "jwtFile": { "index": 18, "kind": "parameter", "displayName": "Jwt File", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file to read the JWT from at every login, for the jwt and kubernetes logins. The kubernetes login reads \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/token when neither jwt nor jwtFile is set." }, "keyStore": { "index": 19, "kind": "parameter", "displayName": "Key Store", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The file with the TLS client certificate and its private key, which the endpoint presents to HashiCorp Vault: for the cert login, or for a Vault that requires client certificates. A PKCS12 or JKS key store, or PEM with the certificate and its unencrypted private key, in PKCS#8 or, for an RSA key, in PKCS#1." }, "keyStorePassword": { "index": 20, "kind": "parameter", "displayName": "Key Store Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The password of the key store and of its private key, when it is a PKCS12 or JKS key store" }, - "role": { "index": 21, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate." }, + "role": { "index": 21, "kind": "parameter", "displayName": "Role", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the certificate." }, "roleId": { "index": 22, "kind": "parameter", "displayName": "Role Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The role ID of the AppRole, for the approle login" }, "secretId": { "index": 23, "kind": "parameter", "displayName": "Secret Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "The secret ID of the AppRole, for the approle login" }, "token": { "index": 24, "kind": "parameter", "displayName": "Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.hashicorp.vault.HashicorpVaultConfiguration", "configurationField": "configuration", "description": "Token to be used, for the token login" }, diff --git a/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc b/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc index 00b6bfb15a7e0..57e51b1837219 100644 --- a/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc +++ b/components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc @@ -80,7 +80,8 @@ JWT login of Vault has a default role. it, Vault tries every certificate role that trusts the certificate. The login needs the `https` scheme. | `aws-iam` -| `role`: the Vault role of the application, which logs in with its AWS credentials, see <>. +| `role`: the Vault role of the application, which logs in with its AWS credentials, see <>. Without +`role`, Vault takes the role named as the IAM principal of the application. | `azure-msi` | `role`: the Vault role of the application, which logs in with its Azure managed identity, see <>. @@ -146,11 +147,33 @@ The `aws-iam` login signs a request to AWS STS with the credentials of the AWS S variables, the system properties, a web identity token (such as IAM roles for service accounts on Amazon EKS), the profile, the container credentials (Amazon ECS) or the instance profile (Amazon EC2). Vault checks the request with STS. The login needs the AWS SDK: add the `software.amazon.awssdk:auth` dependency, in the version of the AWS SDK of -the Camel AWS components. The request is sent to `awsStsEndpoint`, by default the global endpoint -`https://sts.amazonaws.com/`, and signed for `awsRegion`, by default the region of the AWS SDK default region chain -(such as the `AWS_REGION` environment variable). The global endpoint takes requests signed for `us-east-1`; to use a -regional endpoint, set it with its region, as the AWS login of Vault is configured (`sts_endpoint` and `sts_region`). -`awsIamServerId` sets the `X-Vault-AWS-IAM-Server-ID` header, when the AWS login of Vault requires one. +the Camel AWS components. A web identity token also needs the `software.amazon.awssdk:sts` dependency, and an SSO +profile the `software.amazon.awssdk:sso` and `software.amazon.awssdk:ssooidc` dependencies. Without the `sts` +module, the AWS SDK skips the web identity token and takes the next credentials of the chain, such as those of the +instance: so Camel refuses to start the login when a web identity token is set (`AWS_WEB_IDENTITY_TOKEN_FILE`) and +the `sts` module is missing. + +The request is sent to `awsStsEndpoint`, by default the global endpoint `https://sts.amazonaws.com/`, which takes +requests signed for `us-east-1`. Without `awsStsEndpoint` and `awsRegion`, the request is signed for `us-east-1`, +whatever the region of the application, as `vault login -method=aws` does. To use a regional endpoint, set +`awsStsEndpoint` and its region in `awsRegion`, as the AWS login of Vault is configured (`sts_endpoint` and +`sts_region`); without `awsRegion`, the request is then signed for the region of the AWS SDK default region chain, +such as the `AWS_REGION` environment variable. `awsIamServerId` sets the `X-Vault-AWS-IAM-Server-ID` header, when the +AWS login of Vault requires one. + +For example, the properties function logs in with the AWS credentials of the application, through the STS endpoint +of its region: + +[source,properties] +---- +camel.vault.hashicorp.host = vault.example.com +camel.vault.hashicorp.port = 8200 +camel.vault.hashicorp.scheme = https +camel.vault.hashicorp.authentication = aws-iam +camel.vault.hashicorp.role = my-application +camel.vault.hashicorp.awsStsEndpoint = https://sts.eu-west-1.amazonaws.com +camel.vault.hashicorp.awsRegion = eu-west-1 +---- The `azure-msi` login asks the Azure instance metadata service (`169.254.169.254`) for a token of the managed identity of the virtual machine, for the resource `azureResource`, by default `https://management.azure.com/`, which must be @@ -453,14 +476,14 @@ camel.vault.hashicorp.authentication = kubernetes camel.vault.hashicorp.role = my-application ---- -The properties function also reads these options from the environment variables -`CAMEL_HASHICORP_VAULT_AUTHENTICATION`, `CAMEL_HASHICORP_VAULT_ROLE_ID`, `CAMEL_HASHICORP_VAULT_SECRET_ID`, -`CAMEL_HASHICORP_VAULT_ROLE`, `CAMEL_HASHICORP_VAULT_JWT`, `CAMEL_HASHICORP_VAULT_JWT_FILE` and -`CAMEL_HASHICORP_VAULT_AUTH_MOUNT_PATH`, and the settings of <> from `CAMEL_HASHICORP_VAULT_TRUST_STORE`, -`CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD`, `CAMEL_HASHICORP_VAULT_KEY_STORE` and -`CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`, and the settings of the <> from -`CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID`, `CAMEL_HASHICORP_VAULT_AWS_REGION`, `CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT`, -`CAMEL_HASHICORP_VAULT_AZURE_RESOURCE` and `CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the +The properties function also reads these options from the environment variables `CAMEL_HASHICORP_VAULT_AUTHENTICATION`, +`CAMEL_HASHICORP_VAULT_ROLE_ID`, `CAMEL_HASHICORP_VAULT_SECRET_ID`, `CAMEL_HASHICORP_VAULT_ROLE`, +`CAMEL_HASHICORP_VAULT_JWT`, `CAMEL_HASHICORP_VAULT_JWT_FILE` and `CAMEL_HASHICORP_VAULT_AUTH_MOUNT_PATH`, and the +settings of <> from `CAMEL_HASHICORP_VAULT_TRUST_STORE`, `CAMEL_HASHICORP_VAULT_TRUST_STORE_PASSWORD`, +`CAMEL_HASHICORP_VAULT_KEY_STORE` and `CAMEL_HASHICORP_VAULT_KEY_STORE_PASSWORD`, and the settings of the <> from `CAMEL_HASHICORP_VAULT_AWS_IAM_SERVER_ID`, `CAMEL_HASHICORP_VAULT_AWS_REGION`, +`CAMEL_HASHICORP_VAULT_AWS_STS_ENDPOINT`, `CAMEL_HASHICORP_VAULT_AZURE_RESOURCE` and +`CAMEL_HASHICORP_VAULT_AZURE_CLIENT_ID`. When any of the `CAMEL_HASHICORP_VAULT_*` environment variables is set, the properties function takes all its settings from the environment variables, and none from the `camel.vault.hashicorp` configuration. The secret refresh task logs in the same way as the properties function. diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java index cea626d664651..aa1156e6d2914 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultAwsIam.java @@ -26,6 +26,7 @@ import org.springframework.vault.client.VaultClient; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.core.SdkSystemSetting; import software.amazon.awssdk.regions.Region; /** @@ -34,13 +35,35 @@ */ final class HashicorpVaultAwsIam { + // the class of the sts module of the AWS SDK that the web identity provider of the default chain loads + private static final String STS_WEB_IDENTITY_FACTORY + = "software.amazon.awssdk.services.sts.internal.StsWebIdentityCredentialsProviderFactory"; + private HashicorpVaultAwsIam() { } + /** + * Checks that the AWS SDK can use the web identity token of the application, when it has one: without the sts + * module, the default chain skips the web identity token and goes on to other credentials, such as those of the + * instance, so the application would log in to Vault as another identity than its own. + * + * @throws IllegalArgumentException when a web identity token is set and the sts module is missing + */ + static void validate() { + // read as the web identity provider of the AWS SDK reads it: system property, then environment variable + if (SdkSystemSetting.AWS_WEB_IDENTITY_TOKEN_FILE.getStringValue().isPresent() + && ObjectHelper.loadClass(STS_WEB_IDENTITY_FACTORY, HashicorpVaultAwsIam.class.getClassLoader()) == null) { + throw new IllegalArgumentException( + "The aws-iam login with a web identity token (AWS_WEB_IDENTITY_TOKEN_FILE) needs the sts module of the" + + " AWS SDK: add the software.amazon.awssdk:sts dependency"); + } + } + /** * The aws-iam login, which signs its request with the credentials of the AWS SDK default chain: environment - * variables, system properties, web identity token (such as IAM roles for service accounts on EKS), profile, - * container (ECS) or instance profile (EC2). + * variables, system properties, web identity token (such as IAM roles for service accounts on EKS, with the sts + * module of the AWS SDK), profile (with the sso and ssooidc modules for an SSO profile), container (ECS) or + * instance profile (EC2). * * @param closeOnStop takes the credentials provider, to close with the client */ @@ -53,10 +76,16 @@ static ClientAuthentication authentication( static AwsIamAuthenticationOptions options(HashicorpVaultClientSettings settings, AwsCredentialsProvider credentials) { AwsIamAuthenticationOptions.AwsIamAuthenticationOptionsBuilder builder = AwsIamAuthenticationOptions.builder() - .credentialsProvider(credentials) - .role(settings.getRole()); + .credentialsProvider(credentials); + if (ObjectHelper.isNotEmpty(settings.getRole())) { + // without a role, Vault takes the role named as the IAM principal + builder.role(settings.getRole()); + } if (ObjectHelper.isNotEmpty(settings.getAwsRegion())) { builder.region(Region.of(settings.getAwsRegion())); + } else if (ObjectHelper.isEmpty(settings.getAwsStsEndpoint())) { + // the global endpoint takes requests signed for us-east-1, whatever the region of the application + builder.region(Region.US_EAST_1); } if (ObjectHelper.isNotEmpty(settings.getAwsStsEndpoint())) { builder.endpointUri(URI.create(settings.getAwsStsEndpoint())); diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java index d347acf085d1b..c9ae0996a35dc 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java @@ -176,9 +176,7 @@ public static void validate(HashicorpVaultClientSettings settings) { } } case KUBERNETES -> { - if (ObjectHelper.isEmpty(settings.getRole())) { - throw new IllegalArgumentException("The kubernetes login needs a role"); - } + validateRole(settings, "kubernetes"); validateJwt(settings, "kubernetes"); } case JWT -> { @@ -197,11 +195,12 @@ public static void validate(HashicorpVaultClientSettings settings) { } } case AWS_IAM -> { - validateRole(settings, "aws-iam"); + // no role: Vault takes the role named as the IAM principal if (ObjectHelper.loadClass(AWS_SDK_CLASS, HashicorpVaultClient.class.getClassLoader()) == null) { throw new IllegalArgumentException( "The aws-iam login needs the AWS SDK: add the software.amazon.awssdk:auth dependency"); } + HashicorpVaultAwsIam.validate(); } case AZURE_MSI -> validateRole(settings, "azure-msi"); case GCP_GCE -> validateRole(settings, "gcp-gce"); diff --git a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java index 810dc24b2559c..14ab507b4df40 100644 --- a/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java +++ b/components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultConfiguration.java @@ -153,8 +153,9 @@ public void setSecretId(String secretId) { /** * The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The - * jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the - * certificate role that trusts the certificate. + * jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role + * named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the + * certificate. */ public String getRole() { return role; @@ -261,8 +262,8 @@ public void setAwsIamServerId(String awsIamServerId) { } /** - * The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for - * the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION + * The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: + * us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION * environment variable). */ public String getAwsRegion() { diff --git a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java index eece0eff107d9..88d22510ac4fa 100644 --- a/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java +++ b/components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultCloudLoginTest.java @@ -18,6 +18,8 @@ import java.net.URI; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Base64; import java.util.HashMap; import java.util.List; @@ -28,12 +30,14 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.springframework.vault.authentication.AzureMsiAuthenticationOptions; import org.springframework.vault.authentication.GcpComputeAuthenticationOptions; import org.springframework.vault.support.VaultResponse; import tools.jackson.databind.json.JsonMapper; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -45,7 +49,8 @@ class HashicorpVaultCloudLoginTest { // the AWS SDK default chain reads the credentials and the region from these system properties first - private static final List AWS_PROPERTIES = List.of("aws.accessKeyId", "aws.secretAccessKey", "aws.region"); + private static final List AWS_PROPERTIES + = List.of("aws.accessKeyId", "aws.secretAccessKey", "aws.region", "aws.webIdentityTokenFile"); private final Map savedProperties = new HashMap<>(); private FakeVault vault; @@ -110,7 +115,9 @@ void awsIamLogsInWithARequestSignedForTheRegionAndEndpoint() { } @Test - void awsIamSignsForTheGlobalEndpointAndTheRegionOfTheAwsSdkByDefault() { + void awsIamSignsForUsEast1WithTheGlobalEndpointByDefault() { + // the region of the application, which the global endpoint would refuse + System.setProperty("aws.region", "eu-west-1"); vault.on("auth/my-aws/login", request -> FakeVault.login("aws-token", 3600)); HashicorpVaultClientSettings settings = settings("aws-iam"); settings.setRole("camel"); @@ -127,6 +134,48 @@ void awsIamSignsForTheGlobalEndpointAndTheRegionOfTheAwsSdkByDefault() { assertTrue(authorization.contains("/us-east-1/sts/aws4_request"), authorization); } + @Test + void awsIamSignsForTheRegionOfTheAwsSdkWithARegionalEndpoint() { + System.setProperty("aws.region", "eu-central-1"); + vault.on("auth/aws/login", request -> FakeVault.login("aws-token", 3600)); + HashicorpVaultClientSettings settings = settings("aws-iam"); + settings.setRole("camel"); + settings.setAwsStsEndpoint("https://sts.eu-central-1.amazonaws.com"); + client = HashicorpVaultClient.create(context, this, settings); + + assertEquals("pw", readPassword()); + + Map login = vault.requests("auth/aws/login").get(0).json(); + assertEquals("https://sts.eu-central-1.amazonaws.com", decode(login.get("iam_request_url"))); + Map headers = JsonMapper.builder().build().readValue(decode(login.get("iam_request_headers")), Map.class); + String authorization = ((List) headers.get("Authorization")).get(0).toString(); + assertTrue(authorization.contains("/eu-central-1/sts/aws4_request"), authorization); + } + + @Test + void awsIamLogsInWithoutRoleAsTheRoleOfTheIamPrincipal() { + vault.on("auth/aws/login", request -> FakeVault.login("aws-token", 3600)); + client = HashicorpVaultClient.create(context, this, settings("aws-iam")); + + assertEquals("pw", readPassword()); + assertFalse(vault.requests("auth/aws/login").get(0).json().containsKey("role")); + } + + @Test + void awsIamWithAWebIdentityTokenNeedsTheStsModuleOfTheAwsSdk(@TempDir Path dir) throws Exception { + // the test classpath has the auth module of the AWS SDK, but not its sts module + Path token = dir.resolve("token"); + Files.writeString(token, "web-identity-jwt"); + System.setProperty("aws.webIdentityTokenFile", token.toString()); + HashicorpVaultClientSettings settings = settings("aws-iam"); + + IllegalArgumentException e + = assertThrows(IllegalArgumentException.class, () -> HashicorpVaultClient.validate(settings)); + assertEquals("The aws-iam login with a web identity token (AWS_WEB_IDENTITY_TOKEN_FILE) needs the sts module of the" + + " AWS SDK: add the software.amazon.awssdk:sts dependency", + e.getMessage()); + } + @Test void azureMsiAsksForTheTokenOfTheResourceOfVault() { HashicorpVaultClientSettings settings = settings("azure-msi"); @@ -169,8 +218,8 @@ void gcpGceLogsInAsTheRoleWithTheDefaultServiceAccount() { } @Test - void theCloudLoginsNeedARole() { - for (String login : List.of("aws-iam", "azure-msi", "gcp-gce")) { + void theAzureAndGcpLoginsNeedARole() { + for (String login : List.of("azure-msi", "gcp-gce")) { HashicorpVaultClientSettings settings = settings(login); IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> HashicorpVaultClient.validate(settings)); diff --git a/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java b/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java index 01be424b4e98d..3076cc7107037 100644 --- a/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java +++ b/core/camel-api/src/main/java/org/apache/camel/vault/HashicorpVaultConfiguration.java @@ -149,8 +149,9 @@ public void setSecretId(@Nullable String secretId) { /** * The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The - * jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the - * certificate role that trusts the certificate. + * jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role + * named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the + * certificate. * * @since 4.24 */ @@ -302,8 +303,8 @@ public void setAwsIamServerId(@Nullable String awsIamServerId) { } /** - * The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for - * the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION + * The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: + * us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION * environment variable). * * @since 4.24 diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index 92da963c36b85..0db48e268c8d8 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -594,7 +594,7 @@ { "name": "camel.vault.hashicorp.authentication", "required": false, "description": "How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "enum", "javaType": "java.lang.String", "defaultValue": "token", "secret": false, "enum": [ "token", "approle", "kubernetes", "jwt", "cert", "aws-iam", "azure-msi", "gcp-gce" ] }, { "name": "camel.vault.hashicorp.authMountPath", "required": false, "description": "The path the login method is mounted at in hashicorp vault (without auth\/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.awsIamServerId", "required": false, "description": "The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value)", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, - { "name": "camel.vault.hashicorp.awsRegion", "required": false, "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable).", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.awsRegion", "required": false, "description": "The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION environment variable).", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.awsStsEndpoint", "required": false, "description": "The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint https:\/\/sts.amazonaws.com\/.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.azureClientId", "required": false, "description": "The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.azureResource", "required": false, "description": "The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "defaultValue": "https:\/\/management.azure.com\/", "secret": false }, @@ -608,7 +608,7 @@ { "name": "camel.vault.hashicorp.port", "required": true, "description": "Port to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.refreshEnabled", "required": false, "description": "Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.vault.hashicorp.refreshPeriod", "required": false, "description": "The period (millis) between checking Hashicorp Vault for updated secrets.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "integer", "javaType": "long", "defaultValue": 60000, "secret": false }, - { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, + { "name": "camel.vault.hashicorp.role", "required": false, "description": "The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the certificate.", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.roleId", "required": false, "description": "The role ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, { "name": "camel.vault.hashicorp.scheme", "required": true, "description": "Scheme to access hashicorp vault", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.vault.hashicorp.secretId", "required": false, "description": "The secret ID of the AppRole, for the approle login", "sourceType": "org.apache.camel.vault.HashicorpVaultConfiguration", "type": "string", "javaType": "java.lang.String", "secret": true, "security": "secret" }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index 5c0ec3dc0f216..80c685a6c5808 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -550,7 +550,7 @@ The camel.vault.hashicorp supports 25 options, which are listed below. | `camel.vault.hashicorp.authentication` | How to log in to hashicorp vault: token (a fixed token), approle (a role ID and a secret ID), kubernetes (the service account token of the pod), jwt (a JWT, such as a workload identity token), cert (the TLS client certificate of the keyStore), aws-iam (the AWS credentials of the application), azure-msi (the Azure managed identity) or gcp-gce (the service account of the Google Compute Engine instance). Camel renews the token before it expires, and logs in again when the token can no longer be renewed. | token | String | `camel.vault.hashicorp.authMountPath` | The path the login method is mounted at in hashicorp vault (without auth/), when it is not the default path of the login method: approle, kubernetes, jwt, cert, aws (for aws-iam), azure (for azure-msi) or gcp (for gcp-gce) | | String | `camel.vault.hashicorp.awsIamServerId` | The value of the X-Vault-AWS-IAM-Server-ID header of the aws-iam login, when the AWS login of hashicorp vault requires one (iam_server_id_header_value) | | String -| `camel.vault.hashicorp.awsRegion` | The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint: us-east-1 for the global endpoint. When not set, the region of the AWS SDK default region chain (such as the AWS_REGION environment variable). | | String +| `camel.vault.hashicorp.awsRegion` | The AWS region the aws-iam login signs its request for, which must be the region of awsStsEndpoint. When not set: us-east-1 with the global endpoint, else the region of the AWS SDK default region chain (such as the AWS_REGION environment variable). | | String | `camel.vault.hashicorp.awsStsEndpoint` | The AWS STS endpoint of the aws-iam login, which the AWS login of hashicorp vault must accept (its sts_endpoint). When not set, the global endpoint \https://sts.amazonaws.com/. | | String | `camel.vault.hashicorp.azureClientId` | The client ID of a user-assigned managed identity, for the azure-msi login. When not set, the system-assigned managed identity. | | String | `camel.vault.hashicorp.azureResource` | The resource (audience) of the managed identity token of the azure-msi login, which must be the resource of the Azure login of hashicorp vault | https://management.azure.com/ | String @@ -564,7 +564,7 @@ The camel.vault.hashicorp supports 25 options, which are listed below. | `camel.vault.hashicorp.port` | Port to access hashicorp vault | | String | `camel.vault.hashicorp.refreshEnabled` | Whether to automatically reload Camel upon secrets being updated in Hashicorp Vault. | false | boolean | `camel.vault.hashicorp.refreshPeriod` | The period (millis) between checking Hashicorp Vault for updated secrets. | 60000 | long -| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, and the cert login to let Vault pick the certificate role that trusts the certificate. | | String +| `camel.vault.hashicorp.role` | The hashicorp vault role to log in as, for the kubernetes, jwt, cert, aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out when the login method has a default role, the aws-iam login to log in as the role named as the IAM principal, and the cert login to let Vault pick the certificate role that trusts the certificate. | | String | `camel.vault.hashicorp.roleId` | The role ID of the AppRole, for the approle login | | String | `camel.vault.hashicorp.scheme` | Scheme to access hashicorp vault | | String | `camel.vault.hashicorp.secretId` | The secret ID of the AppRole, for the approle login | | String diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java index 82c9ff8f6e10c..eb4a434e67346 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HashicorpVaultEndpointBuilderFactory.java @@ -266,9 +266,9 @@ default HashicorpVaultEndpointBuilder awsIamServerId(String awsIamServerId) { } /** * The AWS region the aws-iam login signs its request for, which must be - * the region of awsStsEndpoint: us-east-1 for the global endpoint. When - * not set, the region of the AWS SDK default region chain (such as the - * AWS_REGION environment variable). + * the region of awsStsEndpoint. When not set: us-east-1 with the global + * endpoint, else the region of the AWS SDK default region chain (such + * as the AWS_REGION environment variable). * * The option is a: java.lang.String type. * @@ -398,7 +398,8 @@ default HashicorpVaultEndpointBuilder keyStorePassword(String keyStorePassword) /** * The HashiCorp Vault role to log in as, for the kubernetes, jwt, cert, * aws-iam, azure-msi and gcp-gce logins. The jwt login can leave it out - * when the login method has a default role, and the cert login to let + * when the login method has a default role, the aws-iam login to log in + * as the role named as the IAM principal, and the cert login to let * Vault pick the certificate role that trusts the certificate. * * The option is a: java.lang.String type.