Crossplane FAQ - Where are my claim’s connection details?

TL;DR - Summary

  • Developers consume the infrastructure provisioned for their claim using connection details that Crossplane publishes
  • Platform Engineers must specify exactly what connection details to publish to the developer from all the resources they compose together
  • This is highly customizable, but can be challenging to get correct because each layer in the composition has to define specific details
  • This blog post walks through each step to get connection information successfully published for the developer
  • A small working example can be found in this gist
  • Further details can be found in the official Crossplane documentation in "Understanding Connection Details"

Compositions in Crossplane allows you to assemble specific cloud provider resources of your choosing and expose them as a higher level abstraction for your developers, giving them self-service capability to provision when they need it. The underlying composed resources often have connection details that you’ll want to propagate up to your developers after successful provisioning so they can find the resources and consume them.

A common source of confusion is how to specify exactly what details should be surfaced. It’s not uncommon for platform engineers to build an opinionated API that results in the correct set of resources being provisioned in the cloud, but missing vital connection information for the developers to discover and connect to these resources.

Today’s entry in the Crossplane FAQ series will demystify this process for you and help you confidently answer the challenge of “where are my claim’s connection details?”

Aligning the Moving Parts

Let’s start with a visualization to refresh our memories on the various components and layers involved in composition:

  1. Developer creates a claim (XRC) in their namespace to express their desire to provision infrastructure
  2. A composite resource (XR) is created in response by Crossplane and matched to a composition
  3. A number of child composed resources are created as defined by the XR’s composition

Each child composed resource (e.g. a database, message queue, or even another nested composite resource) in this graph can have its own individual connection details, all of which can be propagated back up to the developer’s claim. The platform engineer who authors the composite resource and its composition needs to define the specific connection details from each of the children that should be aggregated and published back to the developer for consumption, as demonstrated below:

Specifying the details of this “aggregation” can be challenging to get correct, so let’s dive into the details to make it easy!

Critical Elements of a Connection

To get all of these resources and connection details fully wired up, there are 4 steps to take, working from top to bottom of our composition layers:

  1. The claim must specify the secret where the aggregated connection details should be written
    • This is the spec.writeConnectionSecretToRef field in a claim
    • If creating a composite resource directly (without a claim) then this same field must be set on your composite resource instead
  2. The composite resource definition must state which connection details to aggregate from its children to publish to the claim
    • This is the spec.connectionSecretKeys field in a CompositeResourceDefinition
  3. The composition must define where to write its aggregated connection details
    • This is the spec.writeConnectionSecretsToNamespace field in the Composition
  4. Each child composed resource must define the connection details it publishes and where to write them
    • These are the connectionDetails and base.spec.writeConnectionSecretToRef fields of the composed resources

With these high level steps defined, let’s look more deeply at code samples for each.

1. Claim Connection Details

When the developer creates their claim to kick off the infrastructure provisioning process, they specify the name of the Kubernetes secret that Crossplane writes its aggregated connection details to. This is the location the developer will be looking to find the details they need to connect to the resources after provisioning is successful.

All they have to do is specify a name for the spec.writeConnectionSecretToRef field in their claim:

apiVersion: acme.com/v1
kind: AcmeDatabase
metadata:
  name: acme-db-prod
spec:
  storageGB: 15
  writeConnectionSecretToRef:
    name: acme-db-prod-conn

2. Composite Resource Connection Details

The composite resource is a parent for a number of child composed resources. As each of those children can have their own connection details, the parent composite resource needs to decide which connection details from each child to aggregate and then publish for the claim.

This is done in the CompositeResourceDefinition for the composite resource, in the connectionSecretKeys field. The easiest path, if you're okay with everything being exposed to the developer, is to not specify any entries at all. In that case, all available connection details from all the child composed resources will be propagated.

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xacmedatabases.acme.com
spec:
…
  connectionSecretKeys:
    - connectionName
    - publicIP
    - serverCACertificateCert
    - databaseID

If you choose to include specific entries entries in connectionSecretKeys, each should map to a specific connection detail from one of the child composed resources.

3. Composite Resource Connection Details Location

The composite resource also needs to specify the namespace where all of the connection details should be written that it is aggregating together from its children. Take note that this actually happens in the composition that is selected by the composite resource, not on the composite resource itself.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: xacmedatabases.acme.com
spec:
  writeConnectionSecretsToNamespace: crossplane-system
  ...

4. Child Composed Resource Connection Details and Location

Finally, each child composed resource needs to define the connection details it will publish and where to publish them to. This is demonstrated below by 2 separate child composed resources that represent a database instance and a DB within that instance. Some irrelevant details have been omitted, but the important part is that each child resource has the following fields specified:

  • connectionDetails for which connection details to write
  • base.spec.writeConnectionSecretToRef for where to write them
  resources:
    - name: DBInstance
      base:
        apiVersion: sql.gcp.upbound.io/v1beta1
        kind: DatabaseInstance
        spec:
          writeConnectionSecretToRef:
            namespace: crossplane-system
        …
      connectionDetails:
        - fromConnectionSecretKey: connectionName
        - fromConnectionSecretKey: publicIP
        - fromConnectionSecretKey: serverCACertificateCert
  - name: DB
      base:
        apiVersion: sql.gcp.upbound.io/v1beta1
        kind: Database        
        spec:
          writeConnectionSecretToRef:
            namespace: crossplane-system
      …
      connectionDetails:
        - type: FromFieldPath
          name: databaseID
          fromFieldPath: status.atProvider.id

Running the Full Solution

Now that we’ve seen each individual step of publishing connection details to a claim, we can examine the full solution details in the following gist: https://gist.github.com/jbw976/f81016a081f3bea663c98a5af3bf9da6

Assuming the composite resource definition and its composition have been applied to the cluster, the developer can provision an AcmeDatabase resource by applying the claim. It will take a few minutes for the database to be provisioned, but after everything settles down, we can see that the full connection details have been aggregated from the child composed resources and written to the namespace of the claim, exactly where the developer requested them to be written (in a secret called acme-db-prod-conn):

❯ kubectl describe secret
Name:         acme-db-prod-conn
Namespace:    default

Data
====
serverCACertificateCert:  1272 bytes
connectionName:           55 bytes
databaseID:               100 bytes
publicIP:                 12 bytes

The developer is now free to consume the underlying infrastructure resources using these published connection details aggregated from the composite resource and its children.

Answers for all your Questions

Another FAQ has been answered and we of course want to keep the momentum going!

What Crossplane questions do you have on your mind? For any questions or problems with Crossplane that you’d like to see featured in this new FAQ series, just post about it on the Crossplane Slack #documentation channel, and we’ll try to include them in an upcoming post.

Crossplane is a community driven project and we welcome you to join the community and contribute through a variety of opportunities, such as opening and commenting on issues, joining the community meetings, sharing your adoption story, and providing feedback on design docs and pull requests.

We love to hear from the community, as they are exactly what makes this project great. Whether you are a developer, user, or just interested in what we're up to, feel free to join us via one of the following methods:

Keep up with Upbound

* indicates required