content/v1.20/concepts/connection-details.md
Using connection details in Crossplane requires the following components:
writeConnectionSecretToRef.name in a [Claim]({{<ref "../concepts/claims#claim-connection-secrets">}}).writeConnectionSecretsToNamespace value in the [Composition]({{<ref "../concepts/compositions#composite-resource-combined-secret">}}).writeConnectionSecretToRef name and namespace for each resource in the
[Composition]({{<ref "../concepts/compositions#composed-resource-secrets">}}).connectionSecretKeys in a
[CompositeResourceDefinition]({{<ref "../concepts/composite-resource-definitions#manage-connection-secrets">}}).{{<hint "note">}} This guide discusses creating Kubernetes secrets. Crossplane also supports using external secret stores like HashiCorp Vault.
Read the [external secrets store guide]({{<ref "../guides/vault-as-secret-store">}}) for more information on using Crossplane with an external secret store. {{</hint >}}
When a [Provider]({{<ref "../concepts/providers">}}) creates a managed resource, the resource may generate resource-specific details. These details can include usernames, passwords or connection details like an IP address.
Crossplane refers to this information as the connection details or connection secrets.
The Provider defines what information to present as a connection detail from a managed resource.
<!-- vale gitlab.SentenceLength = NO --> <!-- wordy because of type names -->When a managed resource is part of a [Composition]({{<ref "../concepts/compositions">}}), the Composition, [Composite Resource Definition]({{<ref "../concepts/composite-resource-definitions">}}) and optionally, the [Claim]({{<ref "../concepts/claims">}}) define what details are visible and where they're stored.
<!-- vale gitlab.SentenceLength = YES -->{{<hint "note">}} All the following examples use the same set of Compositions, CompositeResourceDefinitions and Claims.
All examples rely on provider-aws-iam to create resources.
{{<expand "Reference Composition" >}}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: xsecrettest.example.org
spec:
writeConnectionSecretsToNamespace: other-namespace
compositeTypeRef:
apiVersion: example.org/v1alpha1
kind: XSecretTest
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
userSelector:
matchControllerRef: true
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: password
type: FromConnectionSecretKey
fromConnectionSecretKey: password
- name: secret
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.secret
- name: smtp
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.ses_smtp_password_v4
patches:
- fromFieldPath: "metadata.uid"
toFieldPath: "spec.writeConnectionSecretToRef.name"
transforms:
- type: string
string:
type: Format
fmt: "%s-secret1"
- name: user
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: User
spec:
forProvider: {}
- name: user2
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: User
metadata:
labels:
docs.crossplane.io: user
spec:
forProvider: {}
- name: key2
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
userSelector:
matchLabels:
docs.crossplane.io: user
writeConnectionSecretToRef:
namespace: docs
name: key2
connectionDetails:
- name: key2-user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: key2-password
type: FromConnectionSecretKey
fromConnectionSecretKey: password
- name: key2-secret
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.secret
- name: key2-smtp
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.ses_smtp_password_v4
patches:
- fromFieldPath: "metadata.uid"
toFieldPath: "spec.writeConnectionSecretToRef.name"
transforms:
- type: string
string:
type: Format
fmt: "%s-secret2"
{{</expand >}}
{{<expand "Reference CompositeResourceDefinition" >}}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xsecrettests.example.org
spec:
group: example.org
connectionSecretKeys:
- user
- password
- secret
- smtp
- key2-user
- key2-password
- key2-secret
- key2-smtp
names:
kind: XSecretTest
plural: xsecrettests
claimNames:
kind: SecretTest
plural: secrettests
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
{{</ expand >}}
{{<expand "Reference Claim" >}}
apiVersion: example.org/v1alpha1
kind: SecretTest
metadata:
name: test-secrets
namespace: default
spec:
writeConnectionSecretToRef:
name: my-access-key-secret
{{</expand >}} {{</hint >}}
When a managed resource creates connection secrets, Crossplane can write the secrets to a [Kubernetes secret]({{<ref "../concepts/managed-resources#publish-secrets-to-kubernetes">}}) or an [external secret store]({{<ref "../concepts/managed-resources#publish-secrets-to-an-external-secrets-store">}}).
<!-- vale gitlab.SentenceLength = YES --> <!-- vale gitlab.Substitutions = YES -->Creating an individual managed resource shows the connection secrets the resource creates.
{{<hint "note" >}} Read the [managed resources]({{<ref "../concepts/managed-resources">}}) documentation for more information on configuring resources and storing connection secrets for individual resources. {{< /hint >}}
For example, create an {{<hover label="mr" line="2">}}AccessKey{{</hover>}} resource and save the connection secrets in a Kubernetes secret named {{<hover label="mr" line="12">}}my-accesskey-secret{{</hover>}} in the {{<hover label="mr" line="11">}}default{{</hover>}} namespace.
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
metadata:
name: test-accesskey
spec:
forProvider:
userSelector:
matchLabels:
docs.crossplane.io: user
writeConnectionSecretToRef:
namespace: default
name: my-accesskey-secret
View the Kubernetes secret to see the connection details from the managed resource. This includes an {{<hover label="mrSecret" line="11">}}attribute.secret{{</hover>}}, {{<hover label="mrSecret" line="12">}}attribute.ses_smtp_password_v4{{</hover>}}, {{<hover label="mrSecret" line="13">}}password{{</hover>}} and {{<hover label="mrSecret" line="14">}}username{{</hover>}}
kubectl describe secret my-accesskey-secret
Name: my-accesskey-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: connection.crossplane.io/v1alpha1
Data
====
attribute.secret: 40 bytes
attribute.ses_smtp_password_v4: 44 bytes
password: 40 bytes
username: 20 bytes
Compositions and CompositeResourceDefinitions require the exact names of the secrets generated by a resource.
Resources in a Composition that create connection details still create a secret object containing their connection details. Crossplane also generates another secret object for each composite resource, containing the secrets from all the defined resources.
For example, a Composition defines two {{<hover label="comp1" line="9">}}AccessKey{{</hover>}} objects. Each {{<hover label="comp1" line="9">}}AccessKey{{</hover>}} writes a connection secrets to the {{<hover label="comp1" line="15">}}name{{</hover>}} inside the {{<hover label="comp1" line="14">}}namespace{{</hover>}} defined by the resource {{<hover label="comp1" line="13">}}writeConnectionSecretToRef{{</hover>}}.
Crossplane also creates a secret object for the entire Composition saved in the namespace defined by {{<hover label="comp1" line="4">}}writeConnectionSecretsToNamespace{{</hover>}} with a Crossplane generated name.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key1
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1-secret
- name: key2
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key2-secret
# Removed for brevity
After applying a Claim, view the Kubernetes secrets to see three secret objects created.
The secret {{<hover label="compGetSec" line="3">}}key1-secret{{</hover>}} is from the resource {{<hover label="comp1" line="6">}}key1{{</hover>}}, {{<hover label="compGetSec" line="4">}}key2-secret{{</hover>}} is from the resource {{<hover label="comp1" line="16">}}key2{{</hover>}}.
Crossplane creates another secret in the namespace {{<hover label="compGetSec" line="5">}}other-namespace{{</hover>}} with the secrets from resource in the Composition.
kubectl get secrets -A
NAMESPACE NAME TYPE DATA AGE
docs key1-secret connection.crossplane.io/v1alpha1 4 4s
docs key2-secret connection.crossplane.io/v1alpha1 4 4s
other-namespace 70975471-c44f-4f6d-bde6-6bbdc9de1eb8 connection.crossplane.io/v1alpha1 0 6s
Although Crossplane creates a secret object, by default, Crossplane doesn't add any data to the object.
kubectl describe secret 70975471-c44f-4f6d-bde6-6bbdc9de1eb8 -n other-namespace
Name: 70975471-c44f-4f6d-bde6-6bbdc9de1eb8
Namespace: other-namespace
Type: connection.crossplane.io/v1alpha1
Data
====
The Composition must list the connection secrets to store for each resource. Use the {{<hover label="comp2" line="16">}}connectionDetails{{</hover>}} object under each resource and define the secret keys the resource creates.
{{<hint "warning">}} You can't change the {{<hover label="comp2" line="16">}}connectionDetails{{</hover>}} of a Composition. You must delete and recreate the Composition to change the {{<hover label="comp2" line="16">}}connectionDetails{{</hover>}}. {{</hint >}}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: password
type: FromConnectionSecretKey
fromConnectionSecretKey: password
- name: secret
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.secret
- name: smtp
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.ses_smtp_password_v4
# Removed for brevity
After applying a Claim the composite resource secret object contains the list of keys listed in the {{<hover label="comp2" line="16">}}connectionDetails{{</hover>}}.
kubectl describe secret -n other-namespace
Name: b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
Namespace: other-namespace
Type: connection.crossplane.io/v1alpha1
Data
====
password: 40 bytes
secret: 40 bytes
smtp: 44 bytes
user: 20 bytes
{{<hint "important">}} If a key isn't listed in the {{<hover label="comp2" line="16">}}connectionDetails{{</hover>}} it isn't stored in the secret object. {{< /hint >}}
If resources produce conflicting keys, create a unique name with a connection details {{<hover label="comp3" line="25">}}name{{</hover>}}.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: key2
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key2
connectionDetails:
- name: key2-user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
The secret object contains both keys, {{<hover label="comp3Sec" line="9">}}username{{</hover>}} and {{<hover label="comp3Sec" line="10">}}key2-user{{</hover>}}
kubectl describe secret -n other-namespace
Name: b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
Namespace: other-namespace
Type: connection.crossplane.io/v1alpha1
Data
====
user: 20 bytes
key2-user: 20 bytes
# Removed for brevity.
The CompositeResourceDefinition (XRD), can restrict which secrets keys are
put in the combined secret and provided to a Claim.
By default an XRD writes all secret keys listed in the composed resource
connectionDetails to the combined secret object.
Limit the keys passed to the combined secret object and Claims with a {{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}} object.
Inside the {{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}} list the secret key names to create. Crossplane only adds the keys listed to the combined secret.
{{<hint "warning">}} When changing the {{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}} of an XRD the change isn't immediately reflected. You have two options to change the keys in the combined secret object.
For example, an XRD may restrict the secrets to only the {{<hover label="xrd" line="5">}}username{{</hover>}}, {{<hover label="xrd" line="6">}}password{{</hover>}} and custom named {{<hover label="xrd" line="7">}}key2-user{{</hover>}} keys.
kind: CompositeResourceDefinition
spec:
# Removed for brevity.
connectionSecretKeys:
- username
- password
- key2-user
The secret from an individual resource contains all the resources detailed in
the Composition's connectionDetails.
kubectl describe secret key1 -n docs
Name: key1
Namespace: docs
Data
====
password: 40 bytes
username: 20 bytes
attribute.secret: 40 bytes
attribute.ses_smtp_password_v4: 44 bytes
The Claim's secret only contains the keys allowed by the XRD {{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}} fields.
kubectl describe secret my-access-key-secret
Name: my-access-key-secret
Data
====
key2-user: 20 bytes
password: 40 bytes
username: 20 bytes
Compositions create a secret object for each resource and an extra secret containing all the secrets from all resources.
Crossplane saves the resource secret objects in the location defined by the resource's {{<hover label="comp4" line="11">}}writeConnectionSecretToRef{{</hover>}}.
Crossplane saves the combined secret with a Crossplane generated name in the namespace defined in the Composition's {{<hover label="comp4" line="4">}}writeConnectionSecretsToNamespace{{</hover>}}.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: key2
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key2
connectionDetails:
- name: key2-user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
If a Claim uses a secret, it's stored in the same namespace as the Claim with the name defined in the Claim's {{<hover label="claim3" line="7">}}writeConnectionSecretToRef{{</hover>}}.
apiVersion: example.org/v1alpha1
kind: SecretTest
metadata:
name: test-secrets
namespace: default
spec:
writeConnectionSecretToRef:
name: my-access-key-secret
After applying the Claim Crossplane creates the following secrets:
writeConnectionSecretsToNamespace. kubectl get secret -A
NAMESPACE NAME TYPE DATA AGE
default my-access-key-secret connection.crossplane.io/v1alpha1 8 29m
docs key1 connection.crossplane.io/v1alpha1 4 31m
docs key2 connection.crossplane.io/v1alpha1 4 31m
other-namespace b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a connection.crossplane.io/v1alpha1 8 31m