docs/content/v1.17/concepts/connection-details.md

21 KiB

title weight description
Connection Details 110 How to create and manage connection details across Crossplane managed resources, composite resources, Compositions and Claims

Using connection details in Crossplane requires the following components:

  • Defining the writeConnectionSecretToRef.name in a [Claim]({{<ref "/master/concepts/claims#claim-connection-secrets">}}).
  • Defining the writeConnectionSecretsToNamespace value in the [Composition]({{<ref "/master/concepts/compositions#composite-resource-combined-secret">}}).
  • Define the writeConnectionSecretToRef name and namespace for each resource in the [Composition]({{<ref "/master/concepts/compositions#composed-resource-secrets">}}).
  • Define the list of secret keys produced by each composed resource with in the [Composition]({{<ref "/master/concepts/compositions">}}).
  • Optionally, define the connectionSecretKeys in a [CompositeResourceDefinition]({{<ref "/master/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. {{}}

Background

When a [Provider]({{<ref "/master/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.

When a managed resource is part of a [Composition]({{<ref "/master/concepts/compositions">}}), the Composition, [Composite Resource Definition]({{<ref "/master/concepts/composite-resource-definitions">}}) and optionally, the [Claim]({{<ref "/master/concepts/claims">}}) define what details are visible and where they're stored.

{{<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: key
          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 "Reference CompositeResourceDefinition" >}}

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xsecrettests.example.org
spec:
  group: example.org
  connectionSecretKeys:
    - username
    - password
    - attribute.secret
    - attribute.ses_smtp_password_v4
    - key2-user
    - key2-pass
    - 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

{{}} {{}}

Connection secrets in a managed resource

When a managed resource creates connection secrets, Crossplane can write the secrets to a [Kubernetes secret]({{<ref "/master/concepts/managed-resources#publish-secrets-to-kubernetes">}}) or an [external secret store]({{<ref "/master/concepts/managed-resources#publish-secrets-to-an-external-secrets-store">}}).

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

{{<hint "note" >}} Read the [managed resources]({{<ref "/master/concepts/managed-resources">}}) documentation for more information on configuring resources and storing connection secrets for individual resources. {{< /hint >}}

For example, create an {{}}AccessKey{{}} resource and save the connection secrets in a Kubernetes secret named {{}}my-accesskey-secret{{}} in the {{}}default{{}} 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 {{}}attribute.secret{{}}, {{}}attribute.ses_smtp_password_v4{{}}, {{}}password{{}} and {{}}username{{}}

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.

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.

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 {{}}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.

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 {{}}connectionDetails{{}} object under each resource and define the secret keys the resource creates.

{{<hint "warning">}} You can't change the {{}}connectionDetails{{}} of a Composition.
You must delete and recreate the Composition to change the {{}}connectionDetails{{}}.
{{}}

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: key
            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 {{}}connectionDetails{{}}.

kubectl describe secret -n other-namespace
Name:         b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
Namespace:    other-namespace

Type:  connection.crossplane.io/v1alpha1

Data
====
username:                        20 bytes
attribute.secret:                40 bytes
attribute.ses_smtp_password_v4:  44 bytes
password:                        40 bytes

{{<hint "important">}} If a key isn't listed in the {{}}connectionDetails{{}} it isn't stored in the secret object. {{< /hint >}}

Managing conflicting secret keys

If resources produce conflicting keys, create a unique name with a connection details {{}}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: 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, {{}}username{{}} and {{}}key2-user{{}}

kubectl describe secret -n other-namespace
Name:         b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
Namespace:    other-namespace

Type:  connection.crossplane.io/v1alpha1

Data
====
username:                        20 bytes
key2-user:                       20 bytes
# 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.

{{<hint "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.

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 {{}}connectionSecretKeys{{}} fields.

kubectl describe secret my-access-key-secret
Name:         my-access-key-secret

Data
====
key2-user:  20 bytes
password:   40 bytes
username:   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{{}}.

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

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:

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