Skip to content

Commit d1cd390

Browse files
committed
[RFC-0010] Introduce feature gate for enabling object-level workload identity
Signed-off-by: Matheus Pimenta <[email protected]>
1 parent a556f82 commit d1cd390

File tree

5 files changed

+82
-5
lines changed

5 files changed

+82
-5
lines changed

apis/meta/conditions.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ const (
152152
// InvalidCELExpressionReason represents the fact that a CEL expression
153153
// in the configuration is invalid.
154154
InvalidCELExpressionReason string = "InvalidCELExpression"
155+
156+
// FeatureGateDisabledReason represents the fact that a feature is trying to
157+
// be used, but the feature gate for that feature is disabled.
158+
FeatureGateDisabledReason string = "FeatureGateDisabled"
155159
)
156160

157161
// ObjectWithConditions describes a Kubernetes resource object with status conditions.

auth/feature_gate.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright 2025 The Flux authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package auth
18+
19+
import (
20+
"fmt"
21+
"os"
22+
)
23+
24+
// FeatureGateObjectLevelWorkloadIdentity is a feature gate that enables the use of
25+
// object-level workload identity for authentication.
26+
const FeatureGateObjectLevelWorkloadIdentity = "ObjectLevelWorkloadIdentity"
27+
28+
// ErrObjectLevelWorkloadIdentityNotEnabled is returned when object-level
29+
// workload identity is attempted but not enabled.
30+
var ErrObjectLevelWorkloadIdentityNotEnabled = fmt.Errorf(
31+
"%s feature gate is not enabled", FeatureGateObjectLevelWorkloadIdentity)
32+
33+
// SetFeatureGates sets the default values for the feature gates.
34+
func SetFeatureGates(features map[string]bool) {
35+
// opt-in from Flux v2.6.
36+
features[FeatureGateObjectLevelWorkloadIdentity] = false
37+
}
38+
39+
// EnvVarEnableObjectLevelWorkloadIdentity is the environment variable that
40+
// enables the use of object-level workload identity for authentication.
41+
const EnvVarEnableObjectLevelWorkloadIdentity = "ENABLE_OBJECT_LEVEL_WORKLOAD_IDENTITY"
42+
43+
// EnableObjectLevelWorkloadIdentity enables the use of object-level workload
44+
// identity for authentication.
45+
func EnableObjectLevelWorkloadIdentity() {
46+
os.Setenv(EnvVarEnableObjectLevelWorkloadIdentity, "true")
47+
}
48+
49+
// IsObjectLevelWorkloadIdentityEnabled returns true if the object-level
50+
// workload identity feature gate is enabled.
51+
func IsObjectLevelWorkloadIdentityEnabled() bool {
52+
return os.Getenv(EnvVarEnableObjectLevelWorkloadIdentity) == "true"
53+
}

auth/get_token.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ func GetToken(ctx context.Context, provider Provider, opts ...Option) (Token, er
4848
var providerIdentity string
4949
var serviceAccountP *corev1.ServiceAccount
5050
if o.ServiceAccount != nil {
51+
// Check the feature gate for object-level workload identity.
52+
if !IsObjectLevelWorkloadIdentityEnabled() {
53+
return nil, ErrObjectLevelWorkloadIdentityNotEnabled
54+
}
55+
5156
// Get service account and prepare a function to create a token for it.
5257
var serviceAccount corev1.ServiceAccount
5358
if err := o.Client.Get(ctx, *o.ServiceAccount, &serviceAccount); err != nil {

auth/get_token_test.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,12 @@ func TestGetToken(t *testing.T) {
211211
}
212212

213213
for _, tt := range []struct {
214-
name string
215-
provider *mockProvider
216-
opts []auth.Option
217-
expectedToken auth.Token
218-
expectedErr string
214+
name string
215+
provider *mockProvider
216+
opts []auth.Option
217+
disableObjectLevel bool
218+
expectedToken auth.Token
219+
expectedErr string
219220
}{
220221
{
221222
name: "controller access token",
@@ -376,12 +377,25 @@ func TestGetToken(t *testing.T) {
376377
},
377378
expectedErr: "failed to parse artifact repository 'some-registry.io/some/artifact': mock error",
378379
},
380+
{
381+
name: "disable object level workload identity",
382+
provider: &mockProvider{},
383+
opts: []auth.Option{
384+
auth.WithServiceAccount(saRef, kubeClient),
385+
},
386+
disableObjectLevel: true,
387+
expectedErr: "ObjectLevelWorkloadIdentity feature gate is not enabled",
388+
},
379389
} {
380390
t.Run(tt.name, func(t *testing.T) {
381391
g := NewWithT(t)
382392

383393
tt.provider.t = t
384394

395+
if !tt.disableObjectLevel {
396+
t.Setenv(auth.EnvVarEnableObjectLevelWorkloadIdentity, "true")
397+
}
398+
385399
token, err := auth.GetToken(ctx, tt.provider, tt.opts...)
386400

387401
if tt.expectedErr != "" {

oci/tests/integration/testapp/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ var (
6767
func main() {
6868
flag.Parse()
6969
if *wiSAName != "" && *wiSANamespace != "" {
70+
auth.EnableObjectLevelWorkloadIdentity()
7071
conf, err := rest.InClusterConfig()
7172
if err != nil {
7273
panic(err)

0 commit comments

Comments
 (0)