diff --git a/_topic_maps/_topic_map.yml b/_topic_maps/_topic_map.yml index 9a26771d5d07..4677b5c8f8ae 100644 --- a/_topic_maps/_topic_map.yml +++ b/_topic_maps/_topic_map.yml @@ -1301,6 +1301,8 @@ Topics: File: zero-trust-manager-install - Name: Deploying Zero Trust Workload Identity Manager operands File: zero-trust-manager-configuration + - Name: Configuring Zero Trust Workload Identity Manager OIDC Federation + File: zero-trust-manager-oidc-federation - Name: Monitoring Zero Trust Workload Identity Manager File: zero-trust-manager-monitoring - Name: Uninstalling Zero Trust Workload Identity Manager diff --git a/modules/zero-trust-manager-config-azure-blob.adoc b/modules/zero-trust-manager-config-azure-blob.adoc new file mode 100644 index 000000000000..9a39f94edfa4 --- /dev/null +++ b/modules/zero-trust-manager-config-azure-blob.adoc @@ -0,0 +1,40 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-configure-azure-blob_{context}"] += Configuring Azure blob storage + +[role="_abstract"] +Create and configure an Azure storage account and container to store blob content for your zero trust environment. This procedure includes enabling blob encryption and retrieving the unique storage account identifier for further configuration. + +.Procedure + +. Create a new storage account that is used to store content by running the following command: ++ +[source,terminal] +---- +$ az storage account create \ + --name ${STORAGE_ACCOUNT} \ + --resource-group ${RESOURCE_GROUP} \ + --location ${LOCATION} \ + --encryption-services blob +---- + +. Obtain the storage ID for the newly created storage account by running the following command: ++ +[source,terminal] +---- +$ export STORAGE_ACCOUNT_ID=$(az storage account show -n ${STORAGE_ACCOUNT} -g ${RESOURCE_GROUP} --query id --out tsv) +---- + +. Create a storage container inside the newly created storage account to provide a location to support the storage of blobs by running the following command: ++ +[source,terminal] +---- +$ az storage container create \ + --account-name ${STORAGE_ACCOUNT} \ + --name ${STORAGE_CONTAINER} \ + --auth-mode login +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-config-azure-identity.adoc b/modules/zero-trust-manager-config-azure-identity.adoc new file mode 100644 index 000000000000..421154422847 --- /dev/null +++ b/modules/zero-trust-manager-config-azure-identity.adoc @@ -0,0 +1,43 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-configure-azure-identity_{context}"] += Configuring an Azure user managed identity + +[role="_abstract"] +Create an Azure user-assigned managed identity and assign it the Storage Blob Data Contributor role. This procedure includes retrieving the identity client ID to authorize access to your Azure storage resources. + +.Procedure + +. Create a new User Managed Identity and then obtain the Client ID of the related Service Principal associated with the User Managed Identity by running the following command: ++ +[source,terminal] +---- +$ az identity create \ + --name ${USER_ASSIGNED_IDENTITY_NAME} \ + --resource-group ${RESOURCE_GROUP} +---- ++ +[source,terminal] +---- +$ export IDENTITY_CLIENT_ID=$(az identity show --resource-group "${RESOURCE_GROUP}" --name "${USER_ASSIGNED_IDENTITY_NAME}" --query 'clientId' -otsv) +---- + +. Retrieve the `CLIENT_ID` of an Azure user-assigned managed identity and save it as an environment variable by running the following command: ++ +[source,terminal] +---- +$ export IDENTITY_CLIENT_ID=$(az identity show --resource-group "${RESOURCE_GROUP}" --name "${USER_ASSIGNED_IDENTITY_NAME}" --query 'clientId' -otsv) +---- + +. Associate a role with the Service Principal associated with the User Managed Identity by running the following command: ++ +[source,terminal] +---- +$ az role assignment create \ + --role "Storage Blob Data Contributor" \ + --assignee "${IDENTITY_CLIENT_ID}" \ + --scope ${STORAGE_ACCOUNT_ID} +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-configure-azure.adoc b/modules/zero-trust-manager-configure-azure.adoc new file mode 100644 index 000000000000..7487bcf89634 --- /dev/null +++ b/modules/zero-trust-manager-configure-azure.adoc @@ -0,0 +1,96 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-configure-azure_{context}"] += Using Entra ID with {azure-first} + +[role="_abstract"] +Integrate Entra ID with {azure-short} by logging in to the Azure CLI, defining environment variables for your resources, and creating a resource group to manage your workload identity components. + +.Prerequisites + +* You have configured the SPIRE OIDC Discovery Provider Route to serve the TLS certificates from a publicly trusted CA. + +.Procedure + +. Log in to Azure by running the following command: ++ +[source,terminal] +---- +$ az login +---- + +. Configure variables for your Azure subscription and tenant by running the following commands: ++ +[source,terminal] +---- +$ export SUBSCRIPTION_ID=$(az account list --query "[?isDefault].id" -o tsv) +---- ++ +[source,terminal] +---- +$ export TENANT_ID=$(az account list --query "[?isDefault].tenantId" -o tsv) +---- ++ +[source,terminal] +---- +$ export LOCATION=centralus +---- ++ +where: + +`SUBSCRIPTION_ID`:: Specifies your unique subscription identifier. + +`TENANT_ID`:: Specifies the ID for your Azure Active Directory instance. + +`LOCATION`:: The Azure region where your resource is created. + +. Define resource variable names by running the following commands: ++ +[source,terminal] +---- +$ export NAME=ztwim +---- ++ +[source,terminal] +---- +$ export RESOURCE_GROUP="${NAME}-rg" +---- ++ +[source,terminal] +---- +$ export STORAGE_ACCOUNT="${NAME}storage" +---- ++ +[source,terminal] +---- +$ export STORAGE_CONTAINER="${NAME}storagecontainer" +---- ++ +[source,terminal] +---- +$ export USER_ASSIGNED_IDENTITY_NAME="${NAME}-identity" +---- ++ +where: + +`NAME`:: Specifies A base name for all resources. + +`RESOURCE_GROUP`:: Specifies the name of the resource group. + +`STORAGE_ACCOUNT`:: Specifies the name for the storage account. + +`STORAGE_CONTAINER`:: Specifies the name for the storage container. + +`USER_ASSIGNED_IDENTITY_NAME`:: Specifies the name for a managed identity. + +. Create the resource group by running the following command: ++ +[source,terminal] +---- +$ az group create \ + --name "${RESOURCE_GROUP}" \ + --location "${LOCATION}" +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-create-demo-app.adoc b/modules/zero-trust-manager-create-demo-app.adoc new file mode 100644 index 000000000000..8c4f1fa68350 --- /dev/null +++ b/modules/zero-trust-manager-create-demo-app.adoc @@ -0,0 +1,51 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-create-demo-app_{context}"] += Creating the demonstration application + +[role="_abstract"] +Verify your zero trust configuration by creating a demonstration application. This procedure includes creating a dedicated namespace and a Secret that stores the Azure tenant, client, and storage identifiers required for authentication. + +.Procedure + +. Set the application name and namespace by running the following commands: ++ +[source,terminal] +---- +$ export APP_NAME=workload-app +---- ++ +[source,terminal] +---- +$ export APP_NAMESPACE=demo +---- + +. Create the namespace by running the following command: ++ +[source,terminal] +---- +$ oc create namespace $APP_NAMESPACE +---- + +. Create the application Secret by running the following command: ++ +[source,terminal] +---- +$ oc apply -f - << EOF +apiVersion: v1 +kind: Secret +metadata: + name: $APP_NAME + namespace: $APP_NAMESPACE +stringData: + AAD_AUTHORITY: https://login.microsoftonline.com/ + AZURE_AUDIENCE: "api://AzureADTokenExchange" + AZURE_TENANT_ID: "${TENANT_ID}" + AZURE_CLIENT_ID: "${IDENTITY_CLIENT_ID}" + BLOB_STORE_ACCOUNT: "${STORAGE_ACCOUNT}" + BLOB_STORE_CONTAINER: "${STORAGE_CONTAINER}" +EOF +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-create-route-oidc.adoc b/modules/zero-trust-manager-create-route-oidc.adoc new file mode 100644 index 000000000000..4bdc108c8a7c --- /dev/null +++ b/modules/zero-trust-manager-create-route-oidc.adoc @@ -0,0 +1,84 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-create-route-oidc_{context}"] += Configuring the external certificate for the managed OIDC discovery provider route + +[role="_abstract"] +To secure OIDC federation, configure an external TLS certificate for the SPIRE OIDC Discovery Provider route by setting up necessary role-based access control (RBAC) permissions and updating the discovery provider custom resource. + +.Prerequisites + +* You have installed {zero-trust-full} 0.2.0 or later. + +* You have deployed the SPIRE Server, SPIRE Agent, SPIFFEE CSI Driver, and the SPIRE OIDC Discovery Provider operands in the cluster. + +* You have installed the {cert-manager-operator}. For more information, link:https://docs.redhat.com/en/documentation/openshift_container_platform/latest/html-single/security_and_compliance/index#cert-manager-operator-install[Installing the cert-manager Operator for Red{nbsp}Hat OpenShift]. + +* You have created a `ClusterIssuer` or `Issuer` configured with a publicly trusted CA service. For example, an Automated Certificate Management Environment (ACME) type `Issuer` with the "Let's Encrypt ACME" service. For more information, see link:https://docs.redhat.com/en/documentation/openshift_container_platform/latest/html-single/security_and_compliance/index#cert-manager-operator-issuer-acme[Configuring an ACME issuer] + +.Procedure + +. Create a `Role` to provide the router service account permissions to read the referenced secret by running the following command: ++ +[source,terminal] +---- +$ oc create role secret-reader \ + --verb=get,list,watch \ + --resource=secrets \ + --resource-name=$TLS_SECRET_NAME \ + -n zero-trust-workload-identity-manager +---- + +. Create a `RoleBinding` resource to bind the router service account with the newly created Role resource by running the following command: ++ +[source,terminal] +---- +$ oc create rolebinding secret-reader-binding \ + --role=secret-reader \ + --serviceaccount=openshift-ingress:router \ + -n zero-trust-workload-identity-manager +---- + +. Configure the `SpireOIDCDIscoveryProvider` Custom Resource (CR) object to reference the Secret generated in the earlier step by running the following command: ++ +[source,terminal] +---- +$ oc patch SpireOIDCDiscoveryProvider cluster --type=merge -p=' +spec: + externalSecretRef: ${TLS_SECRET_NAME} +' +---- + +.Verification + +. In the `SpireOIDCDiscoveryProvider` CR, check if the `ManageRouteReady` condition is set to `True` by running the following command: ++ +[source,terminal] +---- +$ oc wait --for=jsonpath='{.status.conditions[?(@.type=="ManagedRouteReady")].status}'=True SpireOIDCDiscoveryProvider/cluster --timeout=120s +---- + +. Verify that the OIDC endpoint can be accessed securely through HTTPS by running the following command: ++ +[source,terminal] +---- +$ curl https://$JWT_ISSUER_ENDPOINT/.well-known/openid-configuration + +{ + "issuer": "https://$JWT_ISSUER_ENDPOINT", + "jwks_uri": "https://$JWT_ISSUER_ENDPOINT/keys", + "authorization_endpoint": "", + "response_types_supported": [ + "id_token" + ], + "subject_types_supported": [], + "id_token_signing_alg_values_supported": [ + "RS256", + "ES256", + "ES384" + ] +}% +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-deploy-app.adoc b/modules/zero-trust-manager-deploy-app.adoc new file mode 100644 index 000000000000..21adaa7bb870 --- /dev/null +++ b/modules/zero-trust-manager-deploy-app.adoc @@ -0,0 +1,129 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-deploy-app_{context}"] += Deploying the workload application + +[role="_abstract"] +Deploy the workload application by creating a `ServiceAccount and `Deployment resource. This procedure configures the application to interact with the SPIFFE Workload API and includes steps to verify the deployment and retrieve a SPIFFE JSON Web Token (JWT) token. + +.Prerequisites + +* The demonstration application has been created and deployed. + +.Procedure + +. To deploy the application, copy the entire command block provided and paste it directly into your terminal. Press *Enter*. ++ +[source,terminal] +---- +$ oc apply -f - << EOF +apiVersion: v1 +kind: ServiceAccount +metadata: + name: $APP_NAME + namespace: $APP_NAMESPACE +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: $APP_NAME + namespace: $APP_NAMESPACE +spec: + selector: + matchLabels: + app: $APP_NAME + template: + metadata: + labels: + app: $APP_NAME + deployment: $APP_NAME + spec: + serviceAccountName: $APP_NAME + containers: + - name: $APP_NAME + image: "registry.redhat.io/ubi9/python-311:latest" + command: + - /bin/bash + - "-c" + - | + #!/bin/bash + pip install spiffe azure-cli + + cat << EOF > /opt/app-root/src/get-spiffe-token.py + #!/opt/app-root/bin/python + from spiffe import JwtSource + import argparse + parser = argparse.ArgumentParser(description='Retrieve SPIFFE Token.') + parser.add_argument("-a", "--audience", help="The audience to include in the token", required=True) + args = parser.parse_args() + with JwtSource() as source: + jwt_svid = source.fetch_svid(audience={args.audience}) + print(jwt_svid.token) + EOF + + chmod +x /opt/app-root/src/get-spiffe-token.py + while true; do sleep 10; done + envFrom: + - secretRef: + name: $APP_NAME + env: + - name: SPIFFE_ENDPOINT_SOCKET + value: unix:///run/spire/sockets/spire-agent.sock + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + ports: + - containerPort: 8080 + protocol: TCP + volumeMounts: + - name: spiffe-workload-api + mountPath: /run/spire/sockets + readOnly: true + volumes: + - name: spiffe-workload-api + csi: + driver: csi.spiffe.io + readOnly: true +EOF +---- + +.Verification +. Ensure that the `workload-app` pod is running successfully by running the following command: ++ +[source,terminal] +---- +$ oc get pods -n $APP_NAMESPACE +---- ++ +.Example output +[source, terminal] +---- +NAME READY STATUS RESTARTS AGE +workload-app-5f8b9d685b-abcde 1/1 Running 0 60s +---- + +. Retrieve the SPIFFE JWT Token (SVID-JWT): + +.. Get the pod name dynamically by running the following command: ++ +[source,terminal] +---- +$ POD_NAME=$(oc get pods -n $APP_NAMESPACE -l app=$APP_NAME -o jsonpath='{.items[0].metadata.name}') +---- + +.. Run the script inside the pod by running the following command: ++ +[source,terminal] +---- +$ oc exec -it $POD_NAME -n $APP_NAMESPACE -- \ + /opt/app-root/src/get-spiffe-token.py -a "api://AzureADTokenExchange" +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-disabling-route.adoc b/modules/zero-trust-manager-disabling-route.adoc new file mode 100644 index 000000000000..1a07e46b6a5a --- /dev/null +++ b/modules/zero-trust-manager-disabling-route.adoc @@ -0,0 +1,21 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-disabling-route_{context}"] += Disabling a managed route + +[role="_abstract"] +If you want to fully control the behavior of exposing the OIDC Discovery Provider service, you can disable the managed Route based on your requirements. + +.Procedure + +* To manually configure the OIDC Discovery Provider, set `managedRoute` to `false` by running the following command: ++ +[source,terminal] +---- +$ oc patch SpireOIDCDiscoveryProvider cluster --type=merge -p=' +spec: + managedRoute: "false" +---- diff --git a/modules/zero-trust-manager-entraid-oidc-about.adoc b/modules/zero-trust-manager-entraid-oidc-about.adoc new file mode 100644 index 000000000000..c7a3eee365c5 --- /dev/null +++ b/modules/zero-trust-manager-entraid-oidc-about.adoc @@ -0,0 +1,13 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: CONCEPT +[id="zero-trust-manager-entraid-oidc-about_{context}"] + += About the Entra ID OpenID Connect + + +Entra ID is a cloud-based identity and access management service that centralizes user management and access control. Entra ID serves as the identify provider, verifying user identities and issuing and ID token to the application. This token has essential user information, allowing the application to confirm who the user is without managing their credentials. + +Integrating Entra ID OpenID Connect (OIDC) with SPIRE provides workloads with automatic, short-lived cryptographic identities. The SPIRE-issued identities are sent to Entra ID to securely authenticate the service without any static secrets. \ No newline at end of file diff --git a/modules/zero-trust-manager-initialize-vault-oidc.adoc b/modules/zero-trust-manager-initialize-vault-oidc.adoc new file mode 100644 index 000000000000..2b90be5c6415 --- /dev/null +++ b/modules/zero-trust-manager-initialize-vault-oidc.adoc @@ -0,0 +1,81 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-initialize-vault-oidc_{context}"] += Initializing and unsealing Vault + +[role="_abstract"] +Initialize and unseal your HashiCorp Vault instance to enable cryptographic operations. This procedure includes generating unseal keys and a root token, and unsealing the Vault server via the command line. + +The steps to initialize a Vault server are: + +. Initialize and unseal Vault + +. Enable the key-value (KV) secrets engine and store a test secret + +. Configure JSON Web Token (JWT) authentication with SPIRE + +. Deploy a demonstration application + +. Authenticate and retrieve the secret + +.Prerequisites + +* Ensure that Vault is running. + +* Ensure that Vault is not initialized. You can only initialize a Vault server once. + +.Procedure + +. Open a remote shell into the `vault` pod by running the following command: ++ +[source,terminal] +---- +$ oc rsh -n vault statefulset/vault +---- + +. Initialize Vault to get your unseal key and root token by running the following command: ++ +[source,terminal] +---- +$ vault operator init -key-shares=1 -key-threshold=1 -format=json +---- + +. Export the unseal key and root token you received from the earlier command by running the following commands: ++ +[source,terminal] +---- +$ export UNSEAL_KEY= +---- ++ +[source,terminal] +---- +$ export ROOT_TOKEN= +---- + +. Unseal Vault using your unseal key by running the following command: ++ +[source,terminal] +---- +$ vault operator unseal -format=json $UNSEAL_KEY +---- + +. Exit the pod by entering `exit`. + +.Verification + +* To verify that the Vault pod is ready, run the following command: ++ +[source,terminal] +---- +$ oc get pod -n vault +---- ++ +.Example output +[source, terminal] +---- +NAME READY STATUS RESTARTS AGE +vault-0 1/1 Running 0 65d +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-install-vault-oidc.adoc b/modules/zero-trust-manager-install-vault-oidc.adoc new file mode 100644 index 000000000000..2ee670737a86 --- /dev/null +++ b/modules/zero-trust-manager-install-vault-oidc.adoc @@ -0,0 +1,121 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-install-vault-oidc_{context}"] + += Installing Vault + +[role="_abstract"] +Install HashiCorp Vault on {product-title} by using a Helm chart with a custom configuration. This procedure includes creating a values file, exposing the Vault service through a route, and verifying the installation health. + +.Prerequisites + +* Configure a route. For more information, see link:https://docs.redhat.com/en/documentation/openshift_container_platform/latest/html/ingress_and_load_balancing/routes#nw-configuring-routes[Configuring routes] + +* Helm is installed. + +* A command-line JSON processor for easily reading the output from the Vault API. + +* A HashiCorp Helm repository is added. + +.Procedure + +. Create the `vault-helm-value.yaml` file. ++ +[source,yaml] +---- +global: + enabled: true + openshift: true <1> + tlsDisable: true <2> +injector: + enabled: false +server: + ui: + enabled: true + image: + repository: docker.io/hashicorp/vault + tag: "1.19.0" + dataStorage: + enabled: true <3> + size: 1Gi + standalone: + enabled: true <4> + config: | + listener "tcp" { + tls_disable = 1 <5> + address = "[::]:8200" + cluster_address = "[::]:8201" + } + storage "file" { + path = "/vault/data" + } + extraEnvironmentVars: {} +---- ++ +* The `global.openshift` field optimizes the deployment for OpenShift-specific security contexts. + +* The `global.tlsDisable` field disables TLS for Kubernetes objects created by the chart. + +* The `global.server.dataStorage.enabled` field creates a 1Gi persistent volume to store Vault data. + +* The `glogal.server.standalong.enabled` field deploys a single Vault pod. + +* The `global.server.standalone.enabled` field tells the Vault server to not use TLS. + +. Run the `helm install` command: ++ +[source,terminal] +---- +$ helm install vault hashicorp/vault \ + --create-namespace -n vault \ + --values ./vault-helm-value.yaml +---- + +. Expose the Vault service by running the following command: ++ +[source,terminal] +---- +$ oc expose service vault -n vault +---- + +. Set the `VAULT_ADDR` environment variable to retrieve the hostname from the new route and then export it by running the following command: ++ +[source,terminal] +---- +$ export VAULT_ADDR="http://$(oc get route vault -n vault -o jsonpath='{.spec.host}')" +---- ++ +[NOTE] +==== +`http://` is prepended because TLS is disabled. +==== + +.Verification + +* To ensure your Vault instance is running, run the following command: ++ +[source,terminal] +---- +$ curl -s $VAULT_ADDR/v1/sys/health | jq +---- ++ +.Example output + +[source,JSON] +---- +{ + "initialized": true, + "sealed": true, + "standby": true, + "performance_standby": false, + "replication_performance_mode": "disabled", + "replication_dr_mode": "disabled", + "server_time_utc": 1663786574, + "version": "1.19.0", + "cluster_name": "vault-cluster-a1b2c3d4", + "cluster_id": "5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b" +} +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-spiffe-identity-federation.adoc b/modules/zero-trust-manager-spiffe-identity-federation.adoc new file mode 100644 index 000000000000..2282d257895c --- /dev/null +++ b/modules/zero-trust-manager-spiffe-identity-federation.adoc @@ -0,0 +1,25 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-spiffe-identity-federation_{context}"] += Configuring Azure with the SPIFFE identity federation + +[role="_abstract"] +Federate your Azure user-assigned managed identity with a SPIFFE identity by creating a federated credential. This configuration enables the workload application to authenticate to Azure resources securely using a SPIFFE identity provider and subject. + +.Procedure + +* Federate the identities between the User Managed Identity and the SPIFFE identity associated with the workload application by running the following command: ++ +[source,terminal] +---- +$ az identity federated-credential create \ + --name ${NAME} \ + --identity-name ${USER_ASSIGNED_IDENTITY_NAME} \ + --resource-group ${RESOURCE_GROUP} \ + --issuer https://$JWT_ISSUER_ENDPOINT \ + --subject spiffe://$APP_DOMAIN/ns/$APP_NAMESPACE/sa/$APP_NAME \ + --audience api://AzureADTokenExchange +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-vault-authenticate-jwt.adoc b/modules/zero-trust-manager-vault-authenticate-jwt.adoc new file mode 100644 index 000000000000..b186570f76d2 --- /dev/null +++ b/modules/zero-trust-manager-vault-authenticate-jwt.adoc @@ -0,0 +1,136 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-vault-authenticate-jwt_{context}"] += Configuring JSON Web Token authentication with SPIRE + +[role="_abstract"] +Configure HashiCorp Vault to authenticate applications using SPIFFE identities. This procedure includes enabling the JWT authentication method, importing the SPIRE CA bundle, and creating policies and roles that bind specific SPIFFE IDs to Vault access permissions. + +.Prerequisites + +* Make sure that Vault is initialized and unsealed. + +* Ensure that a test secret is stored in the key-value secrets engine. + +.Procedure + +. On your local machine, retrieve the SPIRE Certificate Authority (CA) bundle and save it to a file by running the following command: ++ +[source,terminal] +---- +$ oc get cm -n zero-trust-workload-identity-manager spire-bundle -o jsonpath='{ .data.bundle\.crt }' > oidc_provider_ca.pem +---- + +. Back in the Vault pod shell, create a temporary file and paste the contents of `oidc_provider_ca.pem` into it by running the following command: ++ +[source,terminal] +---- +$ cat << EOF > /tmp/oidc_provider_ca.pem +-----BEGIN CERTIFICATE----- + +-----END CERTIFICATE----- +EOF +---- + +. Set up the necessary environment variables for the JWT configuration by running the following commands: ++ +[source,terminal] +---- +$ export APP_DOMAIN= +---- ++ +[source,terminal] +---- +$ export JWT_ISSUER_ENDPOINT="oidc-discovery.$APP_DOMAIN" +---- ++ +[source,terminal] +---- +$ export OIDC_URL="https://$JWT_ISSUER_ENDPOINT" +---- ++ +[source,terminal] +---- +$ export OIDC_CA_PEM="$(cat /tmp/oidc_provider_ca.pem)" +---- + +. Crate a new environment variable by running the following command: ++ +[source,terminal] +---- +$ export ROLE="${NAME}-role" +---- + +. Enable the JWT authentication method by running the following command: ++ +[source,terminal] +---- +$ vault auth enable jwt +---- + +. Configure you ODIC authentication method by running the following command: ++ +[source,terminal] +---- +$ vault write auth/jwt/config \ + oidc_discovery_url=$OIDC_URL \ + oidc_discovery_ca_pem="$OIDC_CA_PEM" \ + default_role=$ROLE +---- + +. Create a policy named `ztwim-policy` by running the following command: ++ +[source,terminal] +---- +$ export POLICY="${NAME}-policy" +---- + +. Grant read access to the secret you created earlier by running the following command: ++ +[source,terminal] +---- +$ vault policy write $POLICY -< +---- + +. Crate a new environment variable by running the following command: ++ +[source,terminal] +---- +$ export ROLE="${NAME}-role" +---- + +. Use `curl` to send the JWT token to the Vault login endpoint to get a Vault client token by running the following command: ++ +[source,terminal] +---- +$ VAULT_TOKEN=$(curl -s --request POST --data '{ "jwt": "'"${IDENTITY_TOKEN}"'", "role": "'"${ROLE}"'"}' "${VAULT_ADDR}"/v1/auth/jwt/login | jq -r '.auth.client_token') +---- + +.Verification + +* Use the newly acquired Vault token to read the secret from the KV store by running the following command: ++ +[source,terminal] +---- +$ curl -s -H "X-Vault-Token: $VAULT_TOKEN" $VAULT_ADDR/v1/secret/$NAME | jq +---- ++ +You should see the contents of the secret (`"version": "v0.1.0"`) in the output, confirming the entire workflow is successful \ No newline at end of file diff --git a/modules/zero-trust-manager-vault-deploy-demo.adoc b/modules/zero-trust-manager-vault-deploy-demo.adoc new file mode 100644 index 000000000000..ab02c4c001b0 --- /dev/null +++ b/modules/zero-trust-manager-vault-deploy-demo.adoc @@ -0,0 +1,55 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-vault-deploy-demo_{context}"] += Deploying a demonstration application + +[role="_abstract"] +Deploy a demonstration client application to verify identity-based authentication with Vault. This procedure includes creating a namespace and service account, and deploying a workload that integrates with the SPIFFE Container Storage Interface (CSI) driver. + +.Procedure + +. On your local machine, set the environment variables for your application by running the following commands: ++ +[source,terminal] +---- +$ export APP_NAME=client +---- ++ +[source,terminal] +---- +$ export APP_NAMESPACE=demo +---- ++ +[source,terminal] +---- +$ export AUDIENCE=$APP_NAME +---- + +. Apply the Kubernetes manifest to create the namespace, service account, and deployment for the demo app by running the following command. This deployment mounts the SPIFFE CSI driver socket. ++ +[source,terminal] +---- +$ oc apply -f - < +---- ++ +[source,terminal] +---- +$ vault login "${ROOT_TOKEN}" +---- + +. Enable the KV secrets engine at the `secret/` path and create a test secret by running the following commands: ++ +[source,terminal] +---- +$ export NAME=ztwim +---- ++ +[source,terminal] +---- +$ vault secrets enable -path=secret kv +---- ++ +[source,terminal] +---- +$ vault kv put secret/$NAME version=v0.1.0 +---- + +.Verification + +* To verify that the secret is stored correctly, run the following command: ++ +[source,terminal] +---- +$ vault kv get secret/$NAME +---- \ No newline at end of file diff --git a/modules/zero-trust-manager-vault-oidc-about.adoc b/modules/zero-trust-manager-vault-oidc-about.adoc new file mode 100644 index 000000000000..2213a559b652 --- /dev/null +++ b/modules/zero-trust-manager-vault-oidc-about.adoc @@ -0,0 +1,11 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + +:_mod-docs-content-type: CONCEPT +[id="zero-trust-manager-vault-oidc-about_{context}"] + += About Vault OpenID Connect + +[role="_abstract"] +Vault OpenID Connect (OIDC) with SPIRE creates a secure authentication method where Vault uses SPIRE as a trusted OIDC provider. A workload requests a JWT-SVID from its local SPIRE Agent, which has a unique SPIFFE ID. The workload then presents this token to Vault, and Vault validates it against the public keys on the SPIRE Server. If all conditions are met, Vault issues a short-lived Vault token to the workload which the workload can now use to access secrets and perform actions within Vault. \ No newline at end of file diff --git a/modules/zero-trust-manager-verify-blob-access.adoc b/modules/zero-trust-manager-verify-blob-access.adoc new file mode 100644 index 000000000000..e833d310bf66 --- /dev/null +++ b/modules/zero-trust-manager-verify-blob-access.adoc @@ -0,0 +1,72 @@ +// Module included in the following assemblies: +// +// * security/zero_trust_workload_identity_manageer/zero-trust-manager-oidc-federation.adoc + + +:_mod-docs-content-type: PROCEDURE +[id="zero-trust-manager-verify-blob-access_{context}"] += Verifying that the application workload can access the content in the Azure Blob Storage + +[role="_abstract"] +Verify federated access to Azure Blob Storage by retrieving a SPIFFE token from within the application pod, authenticating with the Azure CLI, and uploading a test file to confirm successful identity federation. + +.Prerequisites + +* An Azure Blob Storage has been created. + +.Procedure + +. Retrieve a JWT token from the SPIFFE Workload API by running the following command: ++ +[source,terminal] +---- +$ oc rsh -n $APP_NAMESPACE deployment/$APP_NAME +---- + +. Create and export an environment variable named `TOKEN` by running the following command: ++ +[source,terminal] +---- +$ export TOKEN=$(/opt/app-root/src/get-spiffe-token.py --audience=$AZURE_AUDIENCE) +---- + +. Log in to {azure-short} CLI included within the pod by running the following command: ++ +[source,terminal] +---- +$ az login --service-principal \ + -t ${AZURE_TENANT_ID} \ + -u ${AZURE_CLIENT_ID} \ + --federated-token ${TOKEN} +---- + +. Create a new file with the application workload pod and upload the file to the Blob Storage by running the following command: ++ +[source,terminal] +---- +$ echo “Hello from OpenShift” > openshift-spire-federated-identities.txt +---- + +. Upload a file to the {azure-short} Blog Storage by running the following command: ++ +[source,terminal] +---- +$ az storage blob upload \ + --account-name ${BLOB_STORE_ACCOUNT} \ + --container-name ${BLOB_STORE_CONTAINER} \ + --name openshift-spire-federated-identities.txt \ + --file openshift-spire-federated-identities.txt \ + --auth-mode login +---- + +.Verification +* Confirm the file uploaded successfully by listing the files contained by running the following command: ++ +[source,terminal] +---- +$ az storage blob list \ + --account-name ${BLOB_STORE_ACCOUNT} \ + --container-name ${BLOB_STORE_CONTAINER} \ + --auth-mode login \ + -o table +---- \ No newline at end of file diff --git a/security/zero_trust_workload_identity_manager/zero-trust-manager-oidc-federation.adoc b/security/zero_trust_workload_identity_manager/zero-trust-manager-oidc-federation.adoc new file mode 100644 index 000000000000..20f309444fa6 --- /dev/null +++ b/security/zero_trust_workload_identity_manager/zero-trust-manager-oidc-federation.adoc @@ -0,0 +1,69 @@ +:_mod-docs-content-type: ASSEMBLY +[id="zero-trust-manager-oidc-federation_{context}"] += Zero Trust Workload Identity Manager OIDC federation + +include::_attributes/common-attributes.adoc[] + +:context: zero-trust-manager-oidc-federation + +toc::[] + +{zero-trust-full} integrates with OpenID Connect (OIDC) by allowing a SPIRE server to act as an OIDC provider. This enables workloads to request and receive verifiable JSON Web Tokens - SPIFFE Verifiable Identity Documents (JWT-SVIDs) from the local SPIRE agent. External systems, such as cloud providers, can then use the OIDC discovery endpoint exposed by the SPIRE server to retrieve public keys. + +The following providers are verified to work with SPIRE OIDC federation: + +* Azure Entra ID + +* Vault + +// About the Entra ID OIDC +include::modules/zero-trust-manager-entraid-oidc-about.adoc[leveloffset=+1] + +// configure OIDC route +include::modules/zero-trust-manager-create-route-oidc.adoc[leveloffset=+2] + +// disable a route +include::modules/zero-trust-manager-disabling-route.adoc[leveloffset=+2] + +// configure Azure +include::modules/zero-trust-manager-configure-azure.adoc[leveloffset=+2] + +// configure azure blog +include::modules/zero-trust-manager-config-azure-blob.adoc[leveloffset=+2] + +// configure azure managed identity +include::modules/zero-trust-manager-config-azure-identity.adoc[leveloffset=+2] + +// create demo application +include::modules/zero-trust-manager-create-demo-app.adoc[leveloffset=+2] + +// deploy demo application +include::modules/zero-trust-manager-deploy-app.adoc[leveloffset=+2] + +// deploy demo application +include::modules/zero-trust-manager-spiffe-identity-federation.adoc[leveloffset=+2] + +// verify access to Azure Blob +include::modules/zero-trust-manager-verify-blob-access.adoc[leveloffset=+2] + + +// About the Vault OIDC +include::modules/zero-trust-manager-vault-oidc-about.adoc[leveloffset=+1] + +// Install the Vault OIDC +include::modules/zero-trust-manager-install-vault-oidc.adoc[leveloffset=+2] + +// Initialize the Vault OIDC +include::modules/zero-trust-manager-initialize-vault-oidc.adoc[leveloffset=+2] + +// Enable kv secret +include::modules/zero-trust-manager-vault-enable-kv.adoc[leveloffset=+2] + +// Authenticate the JWT +include::modules/zero-trust-manager-vault-authenticate-jwt.adoc[leveloffset=+2] + +// deploy a demonstration application +include::modules/zero-trust-manager-vault-deploy-demo.adoc[leveloffset=+2] + +// authenticate and retrieve secret +include::modules/zero-trust-manager-vault-authenticate-secret.adoc[leveloffset=+2] \ No newline at end of file