Using connection details in Crossplane requires the following components:

  • Defining the writeConnectionSecretToRef.name in a Claim.
  • Defining the writeConnectionSecretsToNamespace value in the Composition.
  • Define the writeConnectionSecretToRef name and namespace for each resource in the Composition.
  • Define the list of secret keys produced by each composed resource with in the Composition.
  • Optionally, define the connectionSecretKeys in a CompositeResourceDefinition.
Note

This guide discusses creating Kubernetes secrets.
Crossplane also supports using external secret stores like HashiCorp Vault.

Read the external secrets store guide for more information on using Crossplane with an external secret store.

Background

When a Provider 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.

When a managed resource is part of a Composition, the Composition, Composite Resource Definition and optionally, the Claim define what details are visible and where they’re stored.

Note

All the following examples use the same set of Compositions, CompositeResourceDefinitions and Claims.

All examples rely on Upbound provider-aws-iam to create resources.

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3metadata:
 4  name: xsecrettest.example.org
 5spec:
 6  writeConnectionSecretsToNamespace: other-namespace
 7  compositeTypeRef:
 8    apiVersion: example.org/v1alpha1
 9    kind: XSecretTest
10  mode: Pipeline
11  pipeline:
12  - step: patch-and-transform
13    functionRef:
14      name: function-patch-and-transform
15    input:
16      apiVersion: pt.fn.crossplane.io/v1beta1
17      kind: Resources
18      resources:
19      - name: key
20        base:
21          apiVersion: iam.aws.upbound.io/v1beta1
22          kind: AccessKey
23          spec:
24            forProvider:
25              userSelector:
26                matchControllerRef: true
27            writeConnectionSecretToRef:
28              namespace: docs
29              name: key1
30        connectionDetails:
31        - name: user
32          type: FromConnectionSecretKey
33          fromConnectionSecretKey: username
34        - name: password
35          type: FromConnectionSecretKey
36          fromConnectionSecretKey: password
37        - name: key
38          type: FromConnectionSecretKey
39          fromConnectionSecretKey: attribute.secret
40        - name: smtp
41          type: FromConnectionSecretKey
42          fromConnectionSecretKey: attribute.ses_smtp_password_v4
43        patches:
44          - fromFieldPath: "metadata.uid"
45            toFieldPath: "spec.writeConnectionSecretToRef.name"
46            transforms:
47              - type: string
48                string:
49                  type: Format
50                  fmt: "%s-secret1"
51      - name: user
52        base:
53          apiVersion: iam.aws.upbound.io/v1beta1
54          kind: User
55          spec:
56            forProvider: {}
57      - name: user2
58        base:
59          apiVersion: iam.aws.upbound.io/v1beta1
60          kind: User
61          metadata:
62            labels:
63              docs.crossplane.io: user
64          spec:
65            forProvider: {}
66      - name: key2
67        base:
68          apiVersion: iam.aws.upbound.io/v1beta1
69          kind: AccessKey
70          spec:
71            forProvider:
72              userSelector:
73                matchLabels:
74                  docs.crossplane.io: user
75            writeConnectionSecretToRef:
76              namespace: docs
77              name: key2
78        connectionDetails:
79          - name: key2-user
80            type: FromConnectionSecretKey
81            fromConnectionSecretKey: username
82          - name: key2-password
83            type: FromConnectionSecretKey
84            fromConnectionSecretKey: password
85          - name: key2-secret
86            type: FromConnectionSecretKey
87            fromConnectionSecretKey: attribute.secret
88          - name: key2-smtp
89            type: FromConnectionSecretKey
90            fromConnectionSecretKey: attribute.ses_smtp_password_v4
91        patches:
92          - fromFieldPath: "metadata.uid"
93            toFieldPath: "spec.writeConnectionSecretToRef.name"
94            transforms:
95              - type: string
96                string:
97                  type: Format
98                  fmt: "%s-secret2"
99``  `

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: CompositeResourceDefinition
 3metadata:
 4  name: xsecrettests.example.org
 5spec:
 6  group: example.org
 7  connectionSecretKeys:
 8    - username
 9    - password
10    - attribute.secret
11    - attribute.ses_smtp_password_v4
12    - key2-user
13    - key2-pass
14    - key2-secret
15    - key2-smtp
16  names:
17    kind: XSecretTest
18    plural: xsecrettests
19  claimNames:
20    kind: SecretTest
21    plural: secrettests
22  versions:
23  - name: v1alpha1
24    served: true
25    referenceable: true
26    schema:
27      openAPIV3Schema:
28        type: object
29        properties:
30          spec:
31            type: object

1apiVersion: example.org/v1alpha1
2kind: SecretTest
3metadata:
4  name: test-secrets
5  namespace: default
6spec:
7  writeConnectionSecretToRef:
8    name: my-access-key-secret

Connection secrets in a managed resource

When a managed resource creates connection secrets, Crossplane can write the secrets to a Kubernetes secret or an external secret store.

Creating an individual managed resource shows the connection secrets the resource creates.

Note
Read the managed resources documentation for more information on configuring resources and storing connection secrets for individual resources.

For example, create an AccessKey resource and save the connection secrets in a Kubernetes secret named my-accesskey-secret in the default namespace.

 1apiVersion: iam.aws.upbound.io/v1beta1
 2kind: AccessKey
 3metadata:
 4    name: test-accesskey
 5spec:
 6    forProvider:
 7        userSelector:
 8            matchLabels:
 9                docs.crossplane.io: user
10    writeConnectionSecretToRef:
11        namespace: default
12        name: my-accesskey-secret

View the Kubernetes secret to see the connection details from the managed resource.
This includes an attribute.secret, attribute.ses_smtp_password_v4, password and username

 1kubectl describe secret my-accesskey-secret
 2Name:         my-accesskey-secret
 3Namespace:    default
 4Labels:       <none>
 5Annotations:  <none>
 6
 7Type:  connection.crossplane.io/v1alpha1
 8
 9Data
10====
11attribute.secret:                40 bytes
12attribute.ses_smtp_password_v4:  44 bytes
13password:                        40 bytes
14username:                        20 bytes

Compositions and CompositeResourceDefinitions require the exact names of the secrets generated by a resource.

Connection secrets in Compositions

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 AccessKey objects.
Each AccessKey writes a connection secrets to the name inside the namespace defined by the resource writeConnectionSecretToRef.

Crossplane also creates a secret object for the entire Composition saved in the namespace defined by writeConnectionSecretsToNamespace with a Crossplane generated name.

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3spec:
 4  writeConnectionSecretsToNamespace: other-namespace
 5  mode: Pipeline
 6  pipeline:
 7  - step: patch-and-transform
 8    functionRef:
 9      name: function-patch-and-transform
10    input:
11      apiVersion: pt.fn.crossplane.io/v1beta1
12      kind: Resources
13      resources:
14      - name: key1
15        base:
16          apiVersion: iam.aws.upbound.io/v1beta1
17          kind: AccessKey
18          spec:
19            forProvider:
20              # Removed for brevity
21            writeConnectionSecretToRef:
22              namespace: docs
23              name: key1-secret
24      - name: key2
25        base:
26          apiVersion: iam.aws.upbound.io/v1beta1
27          kind: AccessKey
28          spec:
29            forProvider:
30              # Removed for brevity
31            writeConnectionSecretToRef:
32              namespace: docs
33              name: key2-secret
34      # Removed for brevity

After applying a Claim, view the Kubernetes secrets to see three secret objects created.

The secret key1-secret is from the resource key1, key2-secret is from the resource key2.

Crossplane creates another secret in the namespace other-namespace with the secrets from resource in the Composition.

1kubectl get secrets -A
2NAMESPACE           NAME                                   TYPE                                DATA   AGE
3docs                key1-secret                            connection.crossplane.io/v1alpha1   4      4s
4docs                key2-secret                            connection.crossplane.io/v1alpha1   4      4s
5other-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.

1kubectl describe secret 70975471-c44f-4f6d-bde6-6bbdc9de1eb8 -n other-namespace
2Name:         70975471-c44f-4f6d-bde6-6bbdc9de1eb8
3Namespace:    other-namespace
4
5Type:  connection.crossplane.io/v1alpha1
6
7Data
8====

The Composition must list the connection secrets to store for each resource.
Use the connectionDetails object under each resource and define the secret keys the resource creates.

Warning
You can’t change the connectionDetails of a Composition.
You must delete and recreate the Composition to change the connectionDetails.
 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3spec:
 4  writeConnectionSecretsToNamespace: other-namespace
 5  mode: Pipeline
 6  pipeline:
 7  - step: patch-and-transform
 8    functionRef:
 9      name: function-patch-and-transform
10    input:
11      apiVersion: pt.fn.crossplane.io/v1beta1
12      kind: Resources
13      resources:
14      - name: key
15        base:
16          apiVersion: iam.aws.upbound.io/v1beta1
17          kind: AccessKey
18          spec:
19            forProvider:
20              # Removed for brevity
21            writeConnectionSecretToRef:
22              namespace: docs
23              name: key1
24        connectionDetails:
25          - name: user
26            type: FromConnectionSecretKey
27            fromConnectionSecretKey: username
28          - name: password
29            type: FromConnectionSecretKey
30            fromConnectionSecretKey: password
31          - name: key
32            type: FromConnectionSecretKey
33            fromConnectionSecretKey: attribute.secret
34          - name: smtp
35            type: FromConnectionSecretKey
36            fromConnectionSecretKey: attribute.ses_smtp_password_v4
37      # Removed for brevity

After applying a Claim the composite resource secret object contains the list of keys listed in the connectionDetails.

 1kubectl describe secret -n other-namespace
 2Name:         b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
 3Namespace:    other-namespace
 4
 5Type:  connection.crossplane.io/v1alpha1
 6
 7Data
 8====
 9username:                        20 bytes
10attribute.secret:                40 bytes
11attribute.ses_smtp_password_v4:  44 bytes
12password:                        40 bytes
Important
If a key isn’t listed in the connectionDetails it isn’t stored in the secret object.

Managing conflicting secret keys

If resources produce conflicting keys, create a unique name with a connection details name.

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3spec:
 4  writeConnectionSecretsToNamespace: other-namespace
 5  mode: Pipeline
 6  pipeline:
 7  - step: patch-and-transform
 8    functionRef:
 9      name: function-patch-and-transform
10    input:
11      apiVersion: pt.fn.crossplane.io/v1beta1
12      kind: Resources
13      resources:
14      - name: key
15        base:
16          kind: AccessKey
17          spec:
18            # Removed for brevity
19            writeConnectionSecretToRef:
20              namespace: docs
21              name: key1
22        connectionDetails:
23          - name: user
24            type: FromConnectionSecretKey
25            fromConnectionSecretKey: username
26      - name: key2
27        base:
28          kind: AccessKey
29          spec:
30            # Removed for brevity
31            writeConnectionSecretToRef:
32              namespace: docs
33              name: key2
34        connectionDetails:
35          - name: key2-user
36            type: FromConnectionSecretKey
37            fromConnectionSecretKey: username

The secret object contains both keys, username and key2-user

 1kubectl describe secret -n other-namespace
 2Name:         b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
 3Namespace:    other-namespace
 4
 5Type:  connection.crossplane.io/v1alpha1
 6
 7Data
 8====
 9username:                        20 bytes
10key2-user:                       20 bytes
11# Removed for brevity.

Connection secrets in Composite Resource Definitions

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 connectionSecretKeys object.

Inside the connectionSecretKeys list the secret key names to create. Crossplane only adds the keys listed to the combined secret.

Warning
You can’t change the connectionSecretKeys of an XRD. You must delete and recreate the XRD to change the connectionSecretKeys.

For example, an XRD may restrict the secrets to only the username, password and custom named key2-user keys.

1kind: CompositeResourceDefinition
2spec:
3  # Removed for brevity.
4  connectionSecretKeys:
5    - username
6    - password
7    - key2-user

The secret from an individual resource contains all the resources detailed in the Composition’s connectionDetails.

 1kubectl describe secret key1 -n docs
 2Name:         key1
 3Namespace:    docs
 4
 5Data
 6====
 7password:                        40 bytes
 8username:                        20 bytes
 9attribute.secret:                40 bytes
10attribute.ses_smtp_password_v4:  44 bytes

The Claim’s secret only contains the keys allowed by the XRD connectionSecretKeys fields.

1kubectl describe secret my-access-key-secret
2Name:         my-access-key-secret
3
4Data
5====
6key2-user:  20 bytes
7password:   40 bytes
8username:   20 bytes

Secret objects

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 writeConnectionSecretToRef.

Crossplane saves the combined secret with a Crossplane generated name in the namespace defined in the Composition’s writeConnectionSecretsToNamespace.

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3spec:
 4  writeConnectionSecretsToNamespace: other-namespace
 5  mode: Pipeline
 6  pipeline:
 7  - step: patch-and-transform
 8    functionRef:
 9      name: function-patch-and-transform
10    input:
11      apiVersion: pt.fn.crossplane.io/v1beta1
12      kind: Resources
13      resources:
14      - name: key
15        base:
16          kind: AccessKey
17          spec:
18            # Removed for brevity
19            writeConnectionSecretToRef:
20              namespace: docs
21              name: key1
22        connectionDetails:
23          - name: user
24            type: FromConnectionSecretKey
25            fromConnectionSecretKey: username
26      - name: key2
27        base:
28          kind: AccessKey
29          spec:
30            # Removed for brevity
31            writeConnectionSecretToRef:
32              namespace: docs
33              name: key2
34        connectionDetails:
35          - name: key2-user
36            type: FromConnectionSecretKey
37            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 writeConnectionSecretToRef.

1apiVersion: example.org/v1alpha1
2kind: SecretTest
3metadata:
4  name: test-secrets
5  namespace: default
6spec:
7  writeConnectionSecretToRef:
8    name: my-access-key-secret

After applying the Claim Crossplane creates the following secrets:

  • The Claim’s secret, my-access-key-secret in the Claim’s namespace.
  • The first resource’s secret object, key1.
  • The second resource’s secret object, key2.
  • The composite resource secret object in the other-namespace defined by the Composition’s writeConnectionSecretsToNamespace.
1 kubectl get secret -A
2NAMESPACE           NAME                                   TYPE                                DATA   AGE
3default             my-access-key-secret                   connection.crossplane.io/v1alpha1   8      29m
4docs                key1                                   connection.crossplane.io/v1alpha1   4      31m
5docs                key2                                   connection.crossplane.io/v1alpha1   4      31m
6other-namespace     b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a   connection.crossplane.io/v1alpha1   8      31m