Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions config/crds/authzed.com_spicedbclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,29 @@ spec:
identity, sidecar proxy). When true, SecretName and Key are ignored.
type: boolean
type: object
migrationDatastoreURI:
description: |-
MigrationDatastoreURI configures a separate connection string for migrations.
When set, migration jobs use this URI instead of DatastoreURI, enabling
least-privilege credentials for the application while using elevated
credentials only for migrations.
properties:
key:
description: |-
Key is the key within the Secret. Defaults to the standard SpiceDB key
name for this credential (datastore_uri or preshared_key) if omitted.
type: string
secretName:
description: SecretName is the name of the Kubernetes Secret
in the same namespace.
type: string
skip:
description: |-
Skip instructs the operator not to validate or inject this credential.
Use when the credential is provided externally (CSI driver, workload
identity, sidecar proxy). When true, SecretName and Key are ignored.
type: boolean
type: object
migrationSecrets:
description: MigrationSecrets configures the source for the migration
secrets.
Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/authzed/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ type ClusterCredentials struct {
// MigrationSecrets configures the source for the migration secrets.
// +optional
MigrationSecrets *CredentialRef `json:"migrationSecrets,omitempty"`

// MigrationDatastoreURI configures a separate connection string for migrations.
// When set, migration jobs use this URI instead of DatastoreURI, enabling
// least-privilege credentials for the application while using elevated
// credentials only for migrations.
// +optional
MigrationDatastoreURI *CredentialRef `json:"migrationDatastoreURI,omitempty"`
}

// CredentialRef describes where to read a single credential value.
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/authzed/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 26 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ type SpiceConfig struct {
DatastoreURIRef ResolvedCredentialRef
PresharedKeyRef ResolvedCredentialRef
MigrationSecretsRef ResolvedCredentialRef
MigrationDatastoreURIRef ResolvedCredentialRef
ExtraPodLabels map[string]string
ExtraPodAnnotations map[string]string
ExtraServiceAccountAnnotations map[string]string
Expand Down Expand Up @@ -367,6 +368,24 @@ func NewConfig(cluster *v1alpha1.SpiceDBCluster, globalConfig *OperatorConfig, s
Key: key,
}
}

// Resolve MigrationDatastoreURI credential.
// If not specified, migrations use the same DatastoreURI.
if credentials.MigrationDatastoreURI == nil {
// Default: use the same datastore URI for migrations
spiceConfig.MigrationDatastoreURIRef = spiceConfig.DatastoreURIRef
} else if credentials.MigrationDatastoreURI.Skip {
spiceConfig.MigrationDatastoreURIRef = ResolvedCredentialRef{Skip: true}
} else {
key := credentials.MigrationDatastoreURI.Key
if key == "" {
key = "migration_datastore_uri"
}
spiceConfig.MigrationDatastoreURIRef = ResolvedCredentialRef{
SecretName: credentials.MigrationDatastoreURI.SecretName,
Key: key,
}
}
}

if len(migrationConfig.SpannerCredsSecretRef) > 0 {
Expand Down Expand Up @@ -752,9 +771,14 @@ func (c *Config) unpatchedMigrationJob(migrationHash string) *applybatchv1.JobAp
envVars := []*applycorev1.EnvVarApplyConfiguration{
applycorev1.EnvVar().WithName(envPrefix + "_LOG_LEVEL").WithValue(c.MigrationLogLevel),
}
if !c.DatastoreURIRef.Skip {
// Use MigrationDatastoreURIRef for migrations if set, otherwise fall back to DatastoreURIRef.
migrationURIRef := c.MigrationDatastoreURIRef
if migrationURIRef.SecretName == "" && !migrationURIRef.Skip {
migrationURIRef = c.DatastoreURIRef
}
if !migrationURIRef.Skip {
envVars = append(envVars,
applycorev1.EnvVar().WithName(envPrefix+"_DATASTORE_CONN_URI").WithValueFrom(applycorev1.EnvVarSource().WithSecretKeyRef(applycorev1.SecretKeySelector().WithName(c.DatastoreURIRef.SecretName).WithKey(c.DatastoreURIRef.Key))),
applycorev1.EnvVar().WithName(envPrefix+"_DATASTORE_CONN_URI").WithValueFrom(applycorev1.EnvVarSource().WithSecretKeyRef(applycorev1.SecretKeySelector().WithName(migrationURIRef.SecretName).WithKey(migrationURIRef.Key))),
)
}
if !c.MigrationSecretsRef.Skip {
Expand Down
22 changes: 22 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -257,6 +258,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -342,6 +344,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -408,6 +411,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -476,6 +480,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -563,6 +568,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -650,6 +656,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -741,6 +748,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -835,6 +843,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -924,6 +933,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1013,6 +1023,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1104,6 +1115,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1198,6 +1210,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1289,6 +1302,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1382,6 +1396,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1473,6 +1488,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1563,6 +1579,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1654,6 +1671,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1750,6 +1768,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1850,6 +1869,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down Expand Up @@ -1940,6 +1960,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{ //nolint:gosec // this is a test
Expand Down Expand Up @@ -2031,6 +2052,7 @@ func TestNewConfig(t *testing.T) {
DatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
PresharedKeyRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "preshared_key"},
MigrationSecretsRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "migration_secrets"},
MigrationDatastoreURIRef: ResolvedCredentialRef{SecretName: "test-secret", Key: "datastore_uri"},
ProjectLabels: true,
ProjectAnnotations: true,
Passthrough: map[string]string{
Expand Down
Loading
Loading