mirror of
https://github.com/cloudnative-pg/plugin-barman-cloud.git
synced 2026-07-08 18:52:20 +02:00
Compare commits
8 Commits
337e2213e6
...
4b396d4a93
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b396d4a93 | ||
|
|
0bb78879ce | ||
|
|
ef4b711137 | ||
|
|
baf7985d66 | ||
|
|
d244faa5b2 | ||
|
|
c1d963973d | ||
|
|
2a12a52211 | ||
|
|
2a70f54ef8 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -44,7 +44,7 @@ jobs:
|
||||
- name: Install Dagger
|
||||
env:
|
||||
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
|
||||
DAGGER_VERSION: 0.20.8
|
||||
DAGGER_VERSION: 0.21.0
|
||||
run: |
|
||||
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh
|
||||
- name: Run CI task
|
||||
|
||||
2
.github/workflows/release-please.yml
vendored
2
.github/workflows/release-please.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
- name: Install Dagger
|
||||
env:
|
||||
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
|
||||
DAGGER_VERSION: 0.20.8
|
||||
DAGGER_VERSION: 0.21.0
|
||||
run: |
|
||||
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh
|
||||
- name: Create image and manifest
|
||||
|
||||
2
.github/workflows/release-publish.yml
vendored
2
.github/workflows/release-publish.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
- name: Install Dagger
|
||||
env:
|
||||
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
|
||||
DAGGER_VERSION: 0.20.8
|
||||
DAGGER_VERSION: 0.21.0
|
||||
run: |
|
||||
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh
|
||||
- name: Create image and manifest
|
||||
|
||||
12
Taskfile.yml
12
Taskfile.yml
@ -46,7 +46,7 @@ tasks:
|
||||
- wordlist-ordered
|
||||
env:
|
||||
# renovate: datasource=git-refs depName=spellcheck lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
|
||||
DAGGER_SPELLCHECK_SHA: 537e0ddae55ad0344af8f4454de7f27baeee48fa
|
||||
DAGGER_SPELLCHECK_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
|
||||
cmds:
|
||||
- >
|
||||
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/spellcheck@${DAGGER_SPELLCHECK_SHA}
|
||||
@ -60,7 +60,7 @@ tasks:
|
||||
desc: Check for conventional commits
|
||||
env:
|
||||
# renovate: datasource=git-refs depName=commitlint lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
|
||||
DAGGER_COMMITLINT_SHA: 537e0ddae55ad0344af8f4454de7f27baeee48fa
|
||||
DAGGER_COMMITLINT_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
|
||||
cmds:
|
||||
- >
|
||||
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/commitlint@${DAGGER_COMMITLINT_SHA}
|
||||
@ -74,7 +74,7 @@ tasks:
|
||||
- wordlist-ordered
|
||||
env:
|
||||
# renovate: datasource=git-refs depName=uncommitted lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
|
||||
DAGGER_UNCOMMITTED_SHA: 537e0ddae55ad0344af8f4454de7f27baeee48fa
|
||||
DAGGER_UNCOMMITTED_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
|
||||
cmds:
|
||||
- GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/uncommitted@${DAGGER_UNCOMMITTED_SHA} check-uncommitted --source . stdout
|
||||
sources:
|
||||
@ -86,7 +86,7 @@ tasks:
|
||||
- controller-gen
|
||||
env:
|
||||
# renovate: datasource=git-refs depName=crd-gen-refs lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
|
||||
DAGGER_CRDGENREF_SHA: 537e0ddae55ad0344af8f4454de7f27baeee48fa
|
||||
DAGGER_CRDGENREF_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
|
||||
# renovate: datasource=go depName=github.com/elastic/crd-ref-docs
|
||||
CRDREFDOCS_VERSION: v0.3.0
|
||||
cmds:
|
||||
@ -206,7 +206,7 @@ tasks:
|
||||
- start-build-network
|
||||
vars:
|
||||
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
|
||||
DAGGER_VERSION: 0.20.8
|
||||
DAGGER_VERSION: 0.21.0
|
||||
DAGGER_ENGINE_IMAGE: registry.dagger.io/engine:v{{ .DAGGER_VERSION }}
|
||||
cmds:
|
||||
- >
|
||||
@ -381,7 +381,7 @@ tasks:
|
||||
run: once
|
||||
env:
|
||||
# renovate: datasource=git-refs depName=controller-gen lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
|
||||
DAGGER_CONTROLLER_GEN_SHA: 537e0ddae55ad0344af8f4454de7f27baeee48fa
|
||||
DAGGER_CONTROLLER_GEN_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
|
||||
cmds:
|
||||
- >
|
||||
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/controller-gen@${DAGGER_CONTROLLER_GEN_SHA}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
barman[azure,cloud,google,snappy,zstandard,lz4]==3.18.0
|
||||
barman[azure,cloud,google,snappy,zstandard,lz4]==3.19.1
|
||||
setuptools==82.0.1
|
||||
zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
|
||||
|
||||
@ -18,9 +18,9 @@ azure-storage-blob==12.29.0 \
|
||||
--hash=sha256:2824ddd7ebc9056034ebc76b17971a38e9aa5835abb0d565b9700493f2a6c657 \
|
||||
--hash=sha256:ccf8a1bcd5e49df83ab85aab793b579e5ba2eeea2ad8900b2f62ca3a37dc391f
|
||||
# via barman
|
||||
barman==3.18.0 \
|
||||
--hash=sha256:8e752ac93d2f3a61e86b8374185209cae477a638ece7e6f540070f36d28d6997 \
|
||||
--hash=sha256:ff90c44dafa4107b7574142771cdc2611c4cf1af818d93d3e67440a0c81164b9
|
||||
barman==3.19.1 \
|
||||
--hash=sha256:0a6a9e1babf97687732d8b2a3eb79ea95d55246a5257b9433865cb6e755221c0 \
|
||||
--hash=sha256:2f71c4a1f1ba53f694cbdf838bb9906d8ba02b97d1fd3041196e8999bec7a1ee
|
||||
# via -r sidecar-requirements.in
|
||||
boto3==1.43.14 \
|
||||
--hash=sha256:574335744656cfed0b362a0a0467aaf2eb2bf15526edcd02d31d3c661f4b09e4 \
|
||||
@ -788,6 +788,4 @@ zstandard==0.25.0 \
|
||||
setuptools==82.0.1 \
|
||||
--hash=sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9 \
|
||||
--hash=sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb
|
||||
# via
|
||||
# -r sidecar-requirements.in
|
||||
# barman
|
||||
# via -r sidecar-requirements.in
|
||||
|
||||
4
go.mod
4
go.mod
@ -9,7 +9,7 @@ require (
|
||||
github.com/cloudnative-pg/cloudnative-pg v1.29.1
|
||||
github.com/cloudnative-pg/cnpg-i v0.5.0
|
||||
github.com/cloudnative-pg/cnpg-i-machinery v0.4.2
|
||||
github.com/cloudnative-pg/machinery v0.4.0
|
||||
github.com/cloudnative-pg/machinery v0.5.0
|
||||
github.com/onsi/ginkgo/v2 v2.29.0
|
||||
github.com/onsi/gomega v1.41.0
|
||||
github.com/spf13/cobra v1.10.2
|
||||
@ -114,7 +114,7 @@ require (
|
||||
golang.org/x/net v0.53.0 // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/sys v0.45.0 // indirect
|
||||
golang.org/x/term v0.42.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@ -28,8 +28,8 @@ github.com/cloudnative-pg/cnpg-i v0.5.0 h1:/TOzpNT6cwNgrpftTtrnLKdoHgMwd+88vZgXj
|
||||
github.com/cloudnative-pg/cnpg-i v0.5.0/go.mod h1:7Gh4+UzhBpGhr4DreB1GN9wGYfvxwXCXZUyVt3zE/3I=
|
||||
github.com/cloudnative-pg/cnpg-i-machinery v0.4.2 h1:0reS9MtyLYINHXQ/MfxJ9jp39hhBf8e3Qdj+T5Nsq6I=
|
||||
github.com/cloudnative-pg/cnpg-i-machinery v0.4.2/go.mod h1:gvrKabgxXq0zGthXGucemDdsxakLEQDMxn43M4HLW30=
|
||||
github.com/cloudnative-pg/machinery v0.4.0 h1:3sfqrBptH4QQSVB4g10Z+7aiQRnh4g+6AsqsK0ibKaQ=
|
||||
github.com/cloudnative-pg/machinery v0.4.0/go.mod h1:OIwaTYAnLv8PmBmBvEf0BvMK2JBX6J+naTMg9UgV1FQ=
|
||||
github.com/cloudnative-pg/machinery v0.5.0 h1:hhTnkzn+AiN3NmbjCQ6RXj5rfqV3K6arzq6kdXAzcnQ=
|
||||
github.com/cloudnative-pg/machinery v0.5.0/go.mod h1:uuFjqBUjWn0a9uvAk1ixTSzPM0PrjaS+QiKLOIBqLm4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -275,8 +275,8 @@ golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
|
||||
@ -150,18 +150,25 @@ func (impl LifecycleImplementation) reconcileJob(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
useAzureWorkloadIdentity, err := impl.collectAzureWorkloadIdentityUsage(ctx, pluginConfiguration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reconcileJob(ctx, cluster, request, sidecarConfiguration{
|
||||
env: env,
|
||||
certificates: certificates,
|
||||
resources: resources,
|
||||
env: env,
|
||||
certificates: certificates,
|
||||
resources: resources,
|
||||
useAzureWorkloadIdentity: useAzureWorkloadIdentity,
|
||||
})
|
||||
}
|
||||
|
||||
type sidecarConfiguration struct {
|
||||
env []corev1.EnvVar
|
||||
certificates []corev1.VolumeProjection
|
||||
resources corev1.ResourceRequirements
|
||||
additionalArgs []string
|
||||
env []corev1.EnvVar
|
||||
certificates []corev1.VolumeProjection
|
||||
resources corev1.ResourceRequirements
|
||||
additionalArgs []string
|
||||
useAzureWorkloadIdentity bool
|
||||
}
|
||||
|
||||
func reconcileJob(
|
||||
@ -248,11 +255,17 @@ func (impl LifecycleImplementation) reconcilePod(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
useAzureWorkloadIdentity, err := impl.collectAzureWorkloadIdentityUsage(ctx, pluginConfiguration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reconcileInstancePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{
|
||||
env: env,
|
||||
certificates: certificates,
|
||||
resources: resources,
|
||||
additionalArgs: additionalArgs,
|
||||
env: env,
|
||||
certificates: certificates,
|
||||
resources: resources,
|
||||
additionalArgs: additionalArgs,
|
||||
useAzureWorkloadIdentity: useAzureWorkloadIdentity,
|
||||
})
|
||||
}
|
||||
|
||||
@ -306,6 +319,25 @@ func (impl LifecycleImplementation) collectAdditionalInstanceArgs(
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (impl LifecycleImplementation) collectAzureWorkloadIdentityUsage(
|
||||
ctx context.Context,
|
||||
pluginConfiguration *config.PluginConfiguration,
|
||||
) (bool, error) {
|
||||
for _, objectKey := range pluginConfiguration.GetReferredBarmanObjectsKey() {
|
||||
var objectStore barmancloudv1.ObjectStore
|
||||
if err := impl.Client.Get(ctx, objectKey, &objectStore); err != nil {
|
||||
return false, fmt.Errorf("while getting object store %s: %w", objectKey.String(), err)
|
||||
}
|
||||
|
||||
if objectStore.Spec.Configuration.Azure != nil &&
|
||||
objectStore.Spec.Configuration.Azure.UseDefaultAzureCredentials {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func reconcileInstancePod(
|
||||
ctx context.Context,
|
||||
cluster *cnpgv1.Cluster,
|
||||
@ -384,6 +416,13 @@ func reconcilePodSpec(
|
||||
},
|
||||
)
|
||||
|
||||
if config.useAzureWorkloadIdentity {
|
||||
envs = append(envs, corev1.EnvVar{
|
||||
Name: "AZURE_FEDERATED_TOKEN_FILE",
|
||||
Value: azureFederatedTokenFilePath,
|
||||
})
|
||||
}
|
||||
|
||||
envs = append(envs, config.env...)
|
||||
|
||||
baseProbe := &corev1.Probe{
|
||||
@ -471,6 +510,34 @@ func reconcilePodSpec(
|
||||
spec.Volumes = removeVolume(spec.Volumes, barmanCertificatesVolumeName)
|
||||
}
|
||||
|
||||
if config.useAzureWorkloadIdentity {
|
||||
sidecarTemplate.VolumeMounts = ensureVolumeMount(
|
||||
sidecarTemplate.VolumeMounts,
|
||||
corev1.VolumeMount{
|
||||
Name: azureFederatedTokenVolumeName,
|
||||
MountPath: azureFederatedTokenMountPath,
|
||||
ReadOnly: true,
|
||||
},
|
||||
)
|
||||
|
||||
spec.Volumes = ensureVolume(spec.Volumes, corev1.Volume{
|
||||
Name: azureFederatedTokenVolumeName,
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
Projected: &corev1.ProjectedVolumeSource{
|
||||
Sources: []corev1.VolumeProjection{
|
||||
{
|
||||
ServiceAccountToken: &corev1.ServiceAccountTokenProjection{
|
||||
Path: azureFederatedTokenFileName,
|
||||
Audience: azureFederatedTokenAudience,
|
||||
ExpirationSeconds: ptr.To[int64](azureFederatedTokenExpirationSeconds),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if err := injectPluginSidecarPodSpec(spec, &sidecarTemplate, mainContainerName); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -478,6 +545,15 @@ func reconcilePodSpec(
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
azureFederatedTokenVolumeName = "azure-identity-token"
|
||||
azureFederatedTokenMountPath = "/var/run/secrets/azure/tokens"
|
||||
azureFederatedTokenFileName = "azure-identity-token"
|
||||
azureFederatedTokenFilePath = azureFederatedTokenMountPath + "/" + azureFederatedTokenFileName
|
||||
azureFederatedTokenAudience = "api://AzureADTokenExchange"
|
||||
azureFederatedTokenExpirationSeconds = 3600
|
||||
)
|
||||
|
||||
// TODO: move to machinery once the logic is finalized
|
||||
|
||||
// InjectPluginVolumePodSpec injects the plugin volume into a CNPG Pod spec.
|
||||
|
||||
@ -22,6 +22,7 @@ package operator
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
|
||||
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
||||
"github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
|
||||
"github.com/cloudnative-pg/cnpg-i/pkg/lifecycle"
|
||||
@ -387,6 +388,134 @@ var _ = Describe("LifecycleImplementation", func() {
|
||||
Expect(args).To(Equal([]string{"--log-level=info"}))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("collectAzureWorkloadIdentityUsage", func() {
|
||||
It("returns true when any referred object store uses default Azure credentials", func(ctx SpecContext) {
|
||||
ns := "test-ns"
|
||||
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: ns}}
|
||||
pc := &config.PluginConfiguration{
|
||||
Cluster: cluster,
|
||||
BarmanObjectName: "primary-store",
|
||||
RecoveryBarmanObjectName: "recovery-store",
|
||||
}
|
||||
primaryStore := &barmancloudv1.ObjectStore{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: pc.BarmanObjectName, Namespace: ns},
|
||||
Spec: barmancloudv1.ObjectStoreSpec{
|
||||
Configuration: barmanapi.BarmanObjectStoreConfiguration{
|
||||
BarmanCredentials: barmanapi.BarmanCredentials{
|
||||
Azure: &barmanapi.AzureCredentials{UseDefaultAzureCredentials: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
recoveryStore := &barmancloudv1.ObjectStore{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: pc.RecoveryBarmanObjectName, Namespace: ns},
|
||||
}
|
||||
cli := buildClientFunc(primaryStore, recoveryStore).Build()
|
||||
|
||||
impl := LifecycleImplementation{Client: cli}
|
||||
useWorkloadIdentity, err := impl.collectAzureWorkloadIdentityUsage(ctx, pc)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(useWorkloadIdentity).To(BeTrue())
|
||||
})
|
||||
|
||||
It("returns false when none of the referred object stores use default Azure credentials", func(ctx SpecContext) {
|
||||
ns := "test-ns"
|
||||
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: ns}}
|
||||
pc := &config.PluginConfiguration{
|
||||
Cluster: cluster,
|
||||
BarmanObjectName: "primary-store",
|
||||
}
|
||||
primaryStore := &barmancloudv1.ObjectStore{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: pc.BarmanObjectName, Namespace: ns},
|
||||
Spec: barmancloudv1.ObjectStoreSpec{
|
||||
Configuration: barmanapi.BarmanObjectStoreConfiguration{
|
||||
BarmanCredentials: barmanapi.BarmanCredentials{
|
||||
Azure: &barmanapi.AzureCredentials{InheritFromAzureAD: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cli := buildClientFunc(primaryStore).Build()
|
||||
|
||||
impl := LifecycleImplementation{Client: cli}
|
||||
useWorkloadIdentity, err := impl.collectAzureWorkloadIdentityUsage(ctx, pc)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(useWorkloadIdentity).To(BeFalse())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("reconcilePodSpec", func() {
|
||||
It("injects the Azure federated token volume and env when workload identity is enabled", func() {
|
||||
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "cluster-1", Namespace: "ns-1"}}
|
||||
spec := &corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "postgres",
|
||||
Env: []corev1.EnvVar{
|
||||
{Name: "AZURE_CLIENT_ID", Value: "client-id"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := reconcilePodSpec(
|
||||
cluster,
|
||||
spec,
|
||||
"postgres",
|
||||
corev1.Container{Args: []string{"instance"}},
|
||||
sidecarConfiguration{useAzureWorkloadIdentity: true},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(spec.Volumes).To(ContainElement(HaveField("Name", azureFederatedTokenVolumeName)))
|
||||
Expect(spec.InitContainers).To(HaveLen(1))
|
||||
Expect(spec.InitContainers[0].Env).To(ContainElement(corev1.EnvVar{
|
||||
Name: "AZURE_FEDERATED_TOKEN_FILE",
|
||||
Value: azureFederatedTokenFilePath,
|
||||
}))
|
||||
Expect(spec.InitContainers[0].Env).To(ContainElement(corev1.EnvVar{
|
||||
Name: "AZURE_CLIENT_ID",
|
||||
Value: "client-id",
|
||||
}))
|
||||
Expect(spec.InitContainers[0].VolumeMounts).To(ContainElement(corev1.VolumeMount{
|
||||
Name: azureFederatedTokenVolumeName,
|
||||
MountPath: azureFederatedTokenMountPath,
|
||||
ReadOnly: true,
|
||||
}))
|
||||
})
|
||||
|
||||
It("does not override an existing federated token file env", func() {
|
||||
cluster := &cnpgv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "cluster-1", Namespace: "ns-1"}}
|
||||
spec := &corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "postgres",
|
||||
Env: []corev1.EnvVar{
|
||||
{Name: "AZURE_FEDERATED_TOKEN_FILE", Value: "/custom/token"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := reconcilePodSpec(
|
||||
cluster,
|
||||
spec,
|
||||
"postgres",
|
||||
corev1.Container{Args: []string{"instance"}},
|
||||
sidecarConfiguration{useAzureWorkloadIdentity: true},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(spec.InitContainers).To(HaveLen(1))
|
||||
Expect(spec.InitContainers[0].Env).To(ContainElement(corev1.EnvVar{
|
||||
Name: "AZURE_FEDERATED_TOKEN_FILE",
|
||||
Value: "/custom/token",
|
||||
}))
|
||||
Expect(spec.InitContainers[0].Env).NotTo(ContainElement(corev1.EnvVar{
|
||||
Name: "AZURE_FEDERATED_TOKEN_FILE",
|
||||
Value: azureFederatedTokenFilePath,
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Volume utilities", func() {
|
||||
|
||||
@ -272,9 +272,10 @@ flow, which uses [`DefaultAzureCredential`](https://learn.microsoft.com/en-us/py
|
||||
to automatically discover and use available credentials in the following order:
|
||||
|
||||
1. **Environment Variables** — `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, and `AZURE_TENANT_ID` for Service Principal authentication
|
||||
2. **Managed Identity** — Uses the managed identity assigned to the pod
|
||||
3. **Azure CLI** — Uses credentials from the Azure CLI if available
|
||||
4. **Azure PowerShell** — Uses credentials from Azure PowerShell if available
|
||||
2. **Workload Identity** — Uses `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and a federated service account token
|
||||
3. **Managed Identity** — Uses the managed identity assigned to the pod
|
||||
4. **Azure CLI** — Uses credentials from the Azure CLI if available
|
||||
5. **Azure PowerShell** — Uses credentials from Azure PowerShell if available
|
||||
|
||||
This approach is particularly useful for getting started with development and testing; it allows
|
||||
the SDK to attempt multiple authentication mechanisms seamlessly across different environments.
|
||||
@ -295,6 +296,30 @@ spec:
|
||||
[...]
|
||||
```
|
||||
|
||||
When `useDefaultAzureCredentials: true` is set, the plugin sidecar projects a
|
||||
service account token with the Azure workload identity audience and exposes it
|
||||
as `AZURE_FEDERATED_TOKEN_FILE`. If your platform does not already inject
|
||||
`AZURE_CLIENT_ID` and `AZURE_TENANT_ID`, you can provide them through
|
||||
`.spec.instanceSidecarConfiguration.env`:
|
||||
|
||||
```yaml
|
||||
apiVersion: barmancloud.cnpg.io/v1
|
||||
kind: ObjectStore
|
||||
metadata:
|
||||
name: azure-store
|
||||
spec:
|
||||
configuration:
|
||||
destinationPath: "<destination path here>"
|
||||
azureCredentials:
|
||||
useDefaultAzureCredentials: true
|
||||
instanceSidecarConfiguration:
|
||||
env:
|
||||
- name: AZURE_CLIENT_ID
|
||||
value: "<managed-identity-client-id>"
|
||||
- name: AZURE_TENANT_ID
|
||||
value: "<tenant-id>"
|
||||
```
|
||||
|
||||
### Access Key, SAS Token, or Connection String
|
||||
|
||||
Store credentials in a Kubernetes secret:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user