Skip to content

Commit 316edc3

Browse files
committed
Introduce support for SA token credential in OCIRepository
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
1 parent 633247f commit 316edc3

File tree

9 files changed

+359
-17
lines changed

9 files changed

+359
-17
lines changed

api/v1/ocirepository_types.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ const (
5454
)
5555

5656
// OCIRepositorySpec defines the desired state of OCIRepository
57+
// +kubebuilder:validation:XValidation:rule="!has(self.audiences) || size(self.audiences) == 0 || (has(self.credential) && self.credential == 'ServiceAccountToken')", message="spec.audiences can be set only when spec.credential is set to 'ServiceAccountToken'"
58+
// +kubebuilder:validation:XValidation:rule="!has(self.credential) || self.credential != 'ServiceAccountToken' || (has(self.audiences) && size(self.audiences) > 0)", message="spec.audiences must be set when spec.credential is set to 'ServiceAccountToken'"
59+
// +kubebuilder:validation:XValidation:rule="!has(self.credential) || self.credential != 'ServiceAccountToken' || !has(self.provider) || self.provider == 'generic'", message="spec.credential 'ServiceAccountToken' can only be used with spec.provider 'generic'"
5760
type OCIRepositorySpec struct {
5861
// URL is a reference to an OCI artifact repository hosted
5962
// on a remote container registry.
@@ -71,13 +74,32 @@ type OCIRepositorySpec struct {
7174
// +optional
7275
LayerSelector *OCILayerSelector `json:"layerSelector,omitempty"`
7376

74-
// The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'.
75-
// When not specified, defaults to 'generic'.
77+
// Provider is the provider used for authentication, can be 'aws', 'azure',
78+
// 'gcp' or 'generic'. When not specified, defaults to 'generic'.
7679
// +kubebuilder:validation:Enum=generic;aws;azure;gcp
7780
// +kubebuilder:default:=generic
7881
// +optional
7982
Provider string `json:"provider,omitempty"`
8083

84+
// Credential specifies the type of credential that will be sent to the input provider.
85+
// Supported values are:
86+
//
87+
// - ServiceAccountToken: The controller will generate a Kubernetes
88+
// ServiceAccount token and send it as a bearer token in the OCI
89+
// registry calls. If ServiceAccountName is not specified, the
90+
// ServiceAccount of the controller will be used to generate the
91+
// token. Can only be used with the 'generic' provider.
92+
//
93+
// +kubebuilder:validation:Enum=ServiceAccountToken
94+
// +optional
95+
Credential string `json:"credential,omitempty"`
96+
97+
// Audiences specifies the audience claim to be set in JWT credentials,
98+
// like the ServiceAccountToken credential. Required when using JWT
99+
// credentials.
100+
// +optional
101+
Audiences []string `json:"audiences,omitempty"`
102+
81103
// SecretRef contains the secret name containing the registry login
82104
// credentials to resolve image metadata.
83105
// The secret must be of type kubernetes.io/dockerconfigjson.

api/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ spec:
5454
spec:
5555
description: OCIRepositorySpec defines the desired state of OCIRepository
5656
properties:
57+
audiences:
58+
description: |-
59+
Audiences specifies the audience claim to be set in JWT credentials,
60+
like the ServiceAccountToken credential. Required when using JWT
61+
credentials.
62+
items:
63+
type: string
64+
type: array
5765
certSecretRef:
5866
description: |-
5967
CertSecretRef can be given the name of a Secret containing
@@ -75,6 +83,19 @@ spec:
7583
required:
7684
- name
7785
type: object
86+
credential:
87+
description: |-
88+
Credential specifies the type of credential that will be sent to the input provider.
89+
Supported values are:
90+
91+
- ServiceAccountToken: The controller will generate a Kubernetes
92+
ServiceAccount token and send it as a bearer token in the OCI
93+
registry calls. If ServiceAccountName is not specified, the
94+
ServiceAccount of the controller will be used to generate the
95+
token. Can only be used with the 'generic' provider.
96+
enum:
97+
- ServiceAccountToken
98+
type: string
7899
ignore:
79100
description: |-
80101
Ignore overrides the set of excluded patterns in the .sourceignore format
@@ -117,8 +138,8 @@ spec:
117138
provider:
118139
default: generic
119140
description: |-
120-
The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'.
121-
When not specified, defaults to 'generic'.
141+
Provider is the provider used for authentication, can be 'aws', 'azure',
142+
'gcp' or 'generic'. When not specified, defaults to 'generic'.
122143
enum:
123144
- generic
124145
- aws
@@ -253,6 +274,18 @@ spec:
253274
- interval
254275
- url
255276
type: object
277+
x-kubernetes-validations:
278+
- message: spec.audiences can be set only when spec.credential is set
279+
to 'ServiceAccountToken'
280+
rule: '!has(self.audiences) || size(self.audiences) == 0 || (has(self.credential)
281+
&& self.credential == ''ServiceAccountToken'')'
282+
- message: spec.audiences must be set when spec.credential is set to 'ServiceAccountToken'
283+
rule: '!has(self.credential) || self.credential != ''ServiceAccountToken''
284+
|| (has(self.audiences) && size(self.audiences) > 0)'
285+
- message: spec.credential 'ServiceAccountToken' can only be used with
286+
spec.provider 'generic'
287+
rule: '!has(self.credential) || self.credential != ''ServiceAccountToken''
288+
|| !has(self.provider) || self.provider == ''generic'''
256289
status:
257290
default:
258291
observedGeneration: -1

docs/api/v1/source.md

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,8 +1151,42 @@ string
11511151
</td>
11521152
<td>
11531153
<em>(Optional)</em>
1154-
<p>The provider used for authentication, can be &lsquo;aws&rsquo;, &lsquo;azure&rsquo;, &lsquo;gcp&rsquo; or &lsquo;generic&rsquo;.
1155-
When not specified, defaults to &lsquo;generic&rsquo;.</p>
1154+
<p>Provider is the provider used for authentication, can be &lsquo;aws&rsquo;, &lsquo;azure&rsquo;,
1155+
&lsquo;gcp&rsquo; or &lsquo;generic&rsquo;. When not specified, defaults to &lsquo;generic&rsquo;.</p>
1156+
</td>
1157+
</tr>
1158+
<tr>
1159+
<td>
1160+
<code>credential</code><br>
1161+
<em>
1162+
string
1163+
</em>
1164+
</td>
1165+
<td>
1166+
<em>(Optional)</em>
1167+
<p>Credential specifies the type of credential that will be sent to the input provider.
1168+
Supported values are:</p>
1169+
<ul>
1170+
<li>ServiceAccountToken: The controller will generate a Kubernetes
1171+
ServiceAccount token and send it as a bearer token in the OCI
1172+
registry calls. If ServiceAccountName is not specified, the
1173+
ServiceAccount of the controller will be used to generate the
1174+
token. Can only be used with the &lsquo;generic&rsquo; provider.</li>
1175+
</ul>
1176+
</td>
1177+
</tr>
1178+
<tr>
1179+
<td>
1180+
<code>audiences</code><br>
1181+
<em>
1182+
[]string
1183+
</em>
1184+
</td>
1185+
<td>
1186+
<em>(Optional)</em>
1187+
<p>Audiences specifies the audience claim to be set in JWT credentials,
1188+
like the ServiceAccountToken credential. Required when using JWT
1189+
credentials.</p>
11561190
</td>
11571191
</tr>
11581192
<tr>
@@ -3323,8 +3357,42 @@ string
33233357
</td>
33243358
<td>
33253359
<em>(Optional)</em>
3326-
<p>The provider used for authentication, can be &lsquo;aws&rsquo;, &lsquo;azure&rsquo;, &lsquo;gcp&rsquo; or &lsquo;generic&rsquo;.
3327-
When not specified, defaults to &lsquo;generic&rsquo;.</p>
3360+
<p>Provider is the provider used for authentication, can be &lsquo;aws&rsquo;, &lsquo;azure&rsquo;,
3361+
&lsquo;gcp&rsquo; or &lsquo;generic&rsquo;. When not specified, defaults to &lsquo;generic&rsquo;.</p>
3362+
</td>
3363+
</tr>
3364+
<tr>
3365+
<td>
3366+
<code>credential</code><br>
3367+
<em>
3368+
string
3369+
</em>
3370+
</td>
3371+
<td>
3372+
<em>(Optional)</em>
3373+
<p>Credential specifies the type of credential that will be sent to the input provider.
3374+
Supported values are:</p>
3375+
<ul>
3376+
<li>ServiceAccountToken: The controller will generate a Kubernetes
3377+
ServiceAccount token and send it as a bearer token in the OCI
3378+
registry calls. If ServiceAccountName is not specified, the
3379+
ServiceAccount of the controller will be used to generate the
3380+
token. Can only be used with the &lsquo;generic&rsquo; provider.</li>
3381+
</ul>
3382+
</td>
3383+
</tr>
3384+
<tr>
3385+
<td>
3386+
<code>audiences</code><br>
3387+
<em>
3388+
[]string
3389+
</em>
3390+
</td>
3391+
<td>
3392+
<em>(Optional)</em>
3393+
<p>Audiences specifies the audience claim to be set in JWT credentials,
3394+
like the ServiceAccountToken credential. Required when using JWT
3395+
credentials.</p>
33283396
</td>
33293397
</tr>
33303398
<tr>

docs/spec/v1/ocirepositories.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,99 @@ which can be bound as part of the Container Registry Service Agent role.
255255
Take a look at [this guide](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
256256
for more information about setting up GKE Workload Identity.
257257

258+
### Credential
259+
260+
`.spec.credential` is an optional field that specifies the type of credential
261+
to use for authentication.
262+
263+
Supported values are:
264+
265+
- `ServiceAccountToken`
266+
267+
#### ServiceAccountToken
268+
269+
The `ServiceAccountToken` credential type instructs the controller to generate
270+
a Kubernetes ServiceAccount token and use it as a bearer token in OCI registry
271+
calls. This is useful for authenticating with OCI registries that support
272+
Kubernetes ServiceAccount token authentication, such as registries configured
273+
with OIDC federation to trust tokens from a Kubernetes cluster.
274+
275+
When using `ServiceAccountToken`, you must also specify the
276+
[`.spec.audiences`](#audiences) field to set the audience claim in the token.
277+
278+
If `.spec.serviceAccountName` is specified, the controller will generate a
279+
token for that ServiceAccount. Otherwise, the controller's own ServiceAccount
280+
will be used.
281+
282+
**Note:** The `ServiceAccountToken` credential can only be used with the
283+
`generic` provider (or when no provider is specified, which defaults to
284+
`generic`).
285+
286+
Example:
287+
288+
```yaml
289+
---
290+
apiVersion: source.toolkit.fluxcd.io/v1
291+
kind: OCIRepository
292+
metadata:
293+
name: example
294+
namespace: default
295+
spec:
296+
interval: 5m0s
297+
url: oci://registry.example.com/my-org/my-artifact
298+
credential: ServiceAccountToken
299+
audiences:
300+
- registry.example.com
301+
```
302+
303+
To use a specific ServiceAccount for token generation:
304+
305+
```yaml
306+
---
307+
apiVersion: source.toolkit.fluxcd.io/v1
308+
kind: OCIRepository
309+
metadata:
310+
name: example
311+
namespace: default
312+
spec:
313+
interval: 5m0s
314+
url: oci://registry.example.com/my-org/my-artifact
315+
credential: ServiceAccountToken
316+
audiences:
317+
- registry.example.com
318+
serviceAccountName: my-service-account
319+
```
320+
321+
**Note:** When using `.spec.serviceAccountName` with `ServiceAccountToken`,
322+
the controller feature gate `ObjectLevelWorkloadIdentity` must be enabled.
323+
324+
### Audiences
325+
326+
`.spec.audiences` is a field to specify the audience claims to be set in JWT
327+
credentials. This field is required when `.spec.credential` is set to
328+
`ServiceAccountToken`.
329+
330+
The audiences are typically the identifiers of the services that will validate
331+
the token. For OCI registries, this is usually the registry hostname or a
332+
specific audience value configured in the registry's OIDC settings.
333+
334+
Example:
335+
336+
```yaml
337+
---
338+
apiVersion: source.toolkit.fluxcd.io/v1
339+
kind: OCIRepository
340+
metadata:
341+
name: example
342+
namespace: default
343+
spec:
344+
interval: 5m0s
345+
url: oci://registry.example.com/my-org/my-artifact
346+
credential: ServiceAccountToken
347+
audiences:
348+
- registry.example.com
349+
```
350+
258351
### Secret reference
259352

260353
`.spec.secretRef.name` is an optional field to specify a name reference to a

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ require (
2323
github.com/elazarl/goproxy v1.7.2
2424
github.com/fluxcd/cli-utils v0.36.0-flux.15
2525
github.com/fluxcd/pkg/apis/event v0.21.0
26-
github.com/fluxcd/pkg/apis/meta v1.23.0
26+
github.com/fluxcd/pkg/apis/meta v1.24.0
2727
github.com/fluxcd/pkg/artifact v0.5.0
28-
github.com/fluxcd/pkg/auth v0.33.0
28+
github.com/fluxcd/pkg/auth v0.34.1-0.20260118212638-6e3e8ddfe8fe
2929
github.com/fluxcd/pkg/cache v0.12.0
3030
github.com/fluxcd/pkg/git v0.40.0
3131
github.com/fluxcd/pkg/gittestserver v0.23.0

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,12 @@ github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2T
370370
github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4=
371371
github.com/fluxcd/pkg/apis/event v0.21.0 h1:VVl0WmgDXJwDS3Pivkk+31h3fWHbq+BpbNLUF5d61ec=
372372
github.com/fluxcd/pkg/apis/event v0.21.0/go.mod h1:jacQdE6DdxoBsUOLMzEZNtpd4TqtYaiH1DWoyHMSUSo=
373-
github.com/fluxcd/pkg/apis/meta v1.23.0 h1:fLis5YcHnOsyKYptzBtituBm5EWNx13I0bXQsy0FG4s=
374-
github.com/fluxcd/pkg/apis/meta v1.23.0/go.mod h1:UWsIbBPCxYvoVklr2mV2uLFBf/n17dNAmKFjRfApdDo=
373+
github.com/fluxcd/pkg/apis/meta v1.24.0 h1:+e33T4OL9oqMWZSltsgImvi+/Punx42X9NqFlPesH6o=
374+
github.com/fluxcd/pkg/apis/meta v1.24.0/go.mod h1:UWsIbBPCxYvoVklr2mV2uLFBf/n17dNAmKFjRfApdDo=
375375
github.com/fluxcd/pkg/artifact v0.5.0 h1:9voZe+lEBTM2rzKS+SojavNXEL2h77VfefgagfbBPco=
376376
github.com/fluxcd/pkg/artifact v0.5.0/go.mod h1:w/tkU39ogFvO5AAJgNgOd2Da0HEmdh+Yxl+G9L3w/rE=
377-
github.com/fluxcd/pkg/auth v0.33.0 h1:3ccwqpBr8uWEQgl15b7S0PwJ9EgtcKObg4J1jnaof2w=
378-
github.com/fluxcd/pkg/auth v0.33.0/go.mod h1:ZAFC8pNZxhe+7RV2cQO1K9X62HM8BbRBnCE118oY/0A=
377+
github.com/fluxcd/pkg/auth v0.34.1-0.20260118212638-6e3e8ddfe8fe h1:NSz+6rUo31uy9owVgv8NCRbDNh48DQFOPEHVqUZTC5I=
378+
github.com/fluxcd/pkg/auth v0.34.1-0.20260118212638-6e3e8ddfe8fe/go.mod h1:BIz/zxLVz5o8EYQv+2c+ifAeaLq9wr4azXPdWYOU2AY=
379379
github.com/fluxcd/pkg/cache v0.12.0 h1:mabABT3jIfuo84VbIW+qvfqMZ7PbM5tXQgQvA2uo2rc=
380380
github.com/fluxcd/pkg/cache v0.12.0/go.mod h1:HL/9cgBmwCdKIr3JH57rxrGdb7rOgX5Z1eJlHsaV1vE=
381381
github.com/fluxcd/pkg/git v0.40.0 h1:B23gcdNqHQcVpp9P2BU4mrfFXGA8XFYi9mpy+5RDAQA=

0 commit comments

Comments
 (0)