Implementing safe-start in Providers

This document is for an unreleased version of Crossplane.

This document applies to the Crossplane master branch and not to the latest release v1.20.

This guide shows provider developers how to implement safe-start capability in their Crossplane providers. safe-start enables selective resource activation through Managed Resource Definitions (MRDs), improving performance and resource management.

Important
safe-start requires Crossplane v2.0+ and involves significant provider changes. Plan for breaking changes and thorough testing before implementing.

What safe-start provides

safe-start transforms how your provider handles resource installation:

Without safe-start:

  • All resources become MRDs that are automatically active and create CRDs
  • Users get all ~100 resources even if they need only 5
  • Higher memory usage and slower API server responses

With safe-start:

  • All resources become MRDs that are inactive by default
  • Users activate only needed resources through policies
  • Lower resource overhead and better performance

Prerequisites

Before implementing safe-start, ensure you have:

  • Provider built with crossplane-runtime v2.0+
  • Understanding of MRDs and activation policies
  • Test environment with Crossplane v2.0+
  • CI/CD pipeline that can build and test provider changes

Implementation steps

Step 1: Update Provider Metadata

Declare safe-start capability in your provider package metadata:

1apiVersion: meta.pkg.crossplane.io/v1
2kind: Provider
3metadata:
4  name: provider-example
5spec:
6  package: registry.example.com/provider-example:v1.0.0
7  capabilities:
8  - safe-start
Tip
Crossplane supports flexible capability matching. safe-start, safestart, and safe-start are all recognized as the same capability.

Step 2: Update RBAC Permissions

safe-start providers need extra permissions to manage CRDs dynamically. Crossplane’s RBAC manager automatically provides these permissions when you install safe-start providers.

Note
Manual RBAC configuration is only required if you disable Crossplane’s RBAC manager (with --args=--disable-rbac-manager).

Automatically provided permissions:

1# Crossplane RBAC manager grants these permissions automatically
2# safe-start permissions
3- apiGroups: ["apiextensions.k8s.io"]
4  resources: ["customresourcedefinitions"]
5  verbs: ["get", "list", "watch"]

Manual configuration (only if you disable RBAC manager):

 1apiVersion: rbac.authorization.k8s.io/v1
 2kind: ClusterRole
 3metadata:
 4  name: provider-example-system
 5rules:
 6# Existing provider permissions
 7- apiGroups: [""]
 8  resources: ["events"]
 9  verbs: ["create", "update", "patch"]
10- apiGroups: ["example.crossplane.io"]
11  resources: ["*"]
12  verbs: ["*"]
13
14# safe-start permissions
15- apiGroups: ["apiextensions.k8s.io"]
16  resources: ["customresourcedefinitions"]
17  verbs: ["get", "list", "watch"]

Testing safe-start implementation

Integration testing

Test safe-start behavior in a real cluster:

 1#!/bin/bash
 2set -e
 3
 4echo "Starting safe-start integration test..."
 5
 6# Install Crossplane v2.0
 7kubectl create namespace crossplane-system
 8helm install crossplane crossplane-stable/crossplane \
 9  --namespace crossplane-system \
10  --version v2.0.0 \
11  --wait
12
13# Install provider with safe-start
14kubectl apply -f - <<EOF
15apiVersion: pkg.crossplane.io/v1
16kind: Provider
17metadata:
18  name: provider-example
19spec:
20  package: registry.example.com/provider-example:latest
21EOF
22
23# Wait for provider installation
24kubectl wait --for=condition=Healthy provider/provider-example --timeout=300s
25
26# Verify MRDs created but inactive
27echo "Checking MRD states..."
28MRD_COUNT=$(kubectl get mrds --no-headers | wc -l)
29INACTIVE_COUNT=$(kubectl get mrds -o jsonpath='{.items[*].spec.state}' | grep -o "Inactive" | wc -l)
30
31if [ "$MRD_COUNT" -eq "$INACTIVE_COUNT" ]; then
32    echo "✓ All MRDs are inactive as expected"
33else
34    echo "✗ Some MRDs are unexpectedly active"
35    exit 1
36fi
37
38# Test activation policy
39kubectl apply -f - <<EOF  
40apiVersion: apiextensions.crossplane.io/v1alpha1
41kind: ManagedResourceActivationPolicy
42metadata:
43  name: test-policy
44spec:
45  activations:
46  - "databases.rds.aws.example.io"
47EOF
48
49# Wait for activation
50sleep 10
51
52# Verify activation worked
53ACTIVE_COUNT=$(kubectl get mrd databases.rds.aws.example.io -o jsonpath='{.spec.state}' | grep -o "Active" | wc -l)
54if [ "$ACTIVE_COUNT" -eq "1" ]; then
55    echo "✓ MRD activation successful"
56else
57    echo "✗ MRD activation failed"
58    exit 1
59fi
60
61# Test resource creation
62kubectl apply -f - <<EOF
63apiVersion: rds.aws.example.io/v1alpha1
64kind: Database
65metadata:
66  name: test-db
67  namespace: default
68spec:
69  forProvider:
70    engine: postgres
71    region: us-east-1
72EOF
73
74# Verify resource creation
75kubectl wait --for=condition=Ready database/test-db --timeout=300s --namespace default
76
77echo "✓ safe-start integration test passed"

Migration considerations

For existing users

When you add safe-start to an existing provider:

Breaking change considerations:

  • Existing installations continue to work (backward compatibility)
  • New installations have inactive MRDs by default
  • Users need activation policies for new installations

Migration strategy:

 1# Provide migration documentation like:
 2# For users upgrading to safe-start-enabled provider v2.0:
 3
 4# 1. Existing resources continue working unchanged
 5# 2. For new installations, create activation policy:
 6apiVersion: apiextensions.crossplane.io/v1alpha1
 7kind: ManagedResourceActivationPolicy
 8metadata:
 9  name: legacy-compatibility
10spec:
11  activations:
12  - "*.aws.example.io"  # Activate all resources (legacy behavior)

Troubleshooting

Common Issues

MRDs not activating:

1# Check activation policy exists and matches
2kubectl get mrap
3kubectl describe mrap my-policy
4
5# Verify MRD exists  
6kubectl get mrd my-resource.provider.example.io
7kubectl describe mrd my-resource.provider.example.io

CRDs not created:

1# Check MRD controller logs
2kubectl logs -n crossplane-system deployment/provider-example
3
4# Verify RBAC permissions
5kubectl auth can-i create customresourcedefinitions --as=system:serviceaccount:crossplane-system:provider-example

Resource creation fails:

1# Verify MRD is active
2kubectl get mrd my-resource.provider.example.io -o jsonpath='{.spec.state}'
3
4# Check if CRD exists
5kubectl get crd my-resource.provider.example.io
6
7# Look for controller errors
8kubectl describe my-resource my-instance

Best practices

Performance optimization

  • Start with inactive MRDs for providers with >20 resources
  • Document recommended activation patterns for common use cases
  • Provide environment-specific activation policy examples

User experience

  • Include helpful error messages when resources aren’t activated
  • Provide clear migration guides for existing users
  • Document connection details

Testing strategy

  • Test both with and without safe-start in CI
  • Verify activation/deactivation cycles work
  • Test resource creation after activation