Skip to content

Commit fbf223a

Browse files
committed
Implement AuthN and K8S ServiceAccount DockerFile Keychain support
1 parent b6c4efe commit fbf223a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+2906
-2167
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ WORKDIR /app/
66
RUN go mod download -x
77

88
ARG TARGETOS TARGETARCH
9-
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o ./bin/version-checker ./cmd/.
9+
ENV CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH
10+
RUN go build -o ./bin/version-checker ./cmd/.
1011

1112

1213
FROM alpine:3.22.0

cmd/app/app.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ func NewCommand(ctx context.Context) *cobra.Command {
3737
Use: "version-checker",
3838
Short: helpOutput,
3939
Long: helpOutput,
40+
PreRunE: func(cmd *cobra.Command, args []string) error {
41+
return opts.complete()
42+
},
4043
RunE: func(_ *cobra.Command, _ []string) error {
41-
opts.complete()
4244

4345
logLevel, err := logrus.ParseLevel(opts.LogLevel)
4446
if err != nil {
@@ -105,14 +107,14 @@ func NewCommand(ctx context.Context) *cobra.Command {
105107
metricsServer.RoundTripper,
106108
)
107109

108-
client, err := client.New(ctx, log, opts.Client)
110+
clientManager, err := client.NewManager(ctx, log, mgr.GetConfig(), opts.Client)
109111
if err != nil {
110112
return fmt.Errorf("failed to setup image registry clients: %s", err)
111113
}
112114

113115
c := controller.NewPodReconciler(opts.CacheTimeout,
114116
metricsServer,
115-
client,
117+
clientManager,
116118
mgr.GetClient(),
117119
log,
118120
opts.RequeueDuration,

cmd/app/options.go

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515

1616
"github.com/jetstack/version-checker/pkg/api"
1717
"github.com/jetstack/version-checker/pkg/client"
18-
"github.com/jetstack/version-checker/pkg/client/selfhosted"
1918
)
2019

2120
const (
@@ -50,6 +49,14 @@ const (
5049
envSelfhostedTokenPath = "TOKEN_PATH"
5150
envSelfhostedInsecure = "INSECURE"
5251
envSelfhostedCAPath = "CA_PATH"
52+
53+
// Used for kubernetes Credential Discovery
54+
envKeychainServiceAccountName = "AUTH_SERVICE_ACCOUNT_NAME"
55+
envKeychainNamespace = "AUTH_SERVICE_ACCOUNT_NAMESPACE"
56+
envKeychainImagePullSecrets = "AUTH_IMAGE_PULL_SECRETS"
57+
envKeychainUseMountSecrets = "AUTH_USE_MOUNT_SECRETS"
58+
// Duration in which to Refresh Credentials from Service Account
59+
envKeychainRefreshDuration = "AUTH_REFRESH_DURATION"
5360
)
5461

5562
var (
@@ -149,26 +156,63 @@ func (o *Options) addAppFlags(fs *pflag.FlagSet) {
149156
}
150157

151158
func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
159+
160+
/// KEYCHAIN
161+
fs.StringVar(&o.Client.KeyChain.Namespace,
162+
"keychain-namespace", "",
163+
fmt.Sprintf(
164+
"Namespace inside of which service account and imagepullsecrets belong too (%s_%s).",
165+
envPrefix, envKeychainNamespace,
166+
))
167+
168+
fs.StringVar(&o.Client.KeyChain.ServiceAccountName,
169+
"keychain-service-account", "",
170+
fmt.Sprintf(
171+
"ServiceAccount used to fetch Image Pull Secrets from (%s_%s).",
172+
envPrefix, envKeychainServiceAccountName,
173+
))
174+
175+
fs.StringSliceVar(&o.Client.KeyChain.ImagePullSecrets,
176+
"keychain-image-pull-secrets", []string{},
177+
fmt.Sprintf(
178+
"Set of image pull secrets to include during authentication (%s_%s).",
179+
envPrefix, envKeychainImagePullSecrets,
180+
))
181+
182+
fs.BoolVar(&o.Client.KeyChain.UseMountSecrets,
183+
"keychain-use-mount-secrets", false,
184+
fmt.Sprintf("Include Mount Secrets during discovery (%s_%s).",
185+
envPrefix, envKeychainUseMountSecrets,
186+
))
187+
fs.DurationVar(&o.Client.AuthRefreshDuration,
188+
"keychain-refresh-duration", time.Hour,
189+
fmt.Sprintf("Duration credentials are refreshed (%s_%s).",
190+
envPrefix, envKeychainRefreshDuration,
191+
))
192+
152193
/// ACR
153194
fs.StringVar(&o.Client.ACR.Username,
154195
"acr-username", "",
155196
fmt.Sprintf(
156197
"Username to authenticate with azure container registry (%s_%s).",
157198
envPrefix, envACRUsername,
158199
))
200+
_ = fs.MarkDeprecated("acr-username", "use keychain instead")
159201
fs.StringVar(&o.Client.ACR.Password,
160202
"acr-password", "",
161203
fmt.Sprintf(
162204
"Password to authenticate with azure container registry (%s_%s).",
163205
envPrefix, envACRPassword,
164206
))
207+
_ = fs.MarkDeprecated("acr-password", "use keychain instead")
165208
fs.StringVar(&o.Client.ACR.RefreshToken,
166209
"acr-refresh-token", "",
167210
fmt.Sprintf(
168211
"Refresh token to authenticate with azure container registry. Cannot be used with "+
169212
"username/password (%s_%s).",
170213
envPrefix, envACRRefreshToken,
171214
))
215+
_ = fs.MarkDeprecated("acr-refresh-token", "use keychain instead")
172216
fs.StringVar(&o.Client.ACR.JWKSURI,
173217
"acr-jwks-uri", "",
174218
fmt.Sprintf(
@@ -184,19 +228,22 @@ func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
184228
"Username to authenticate with docker registry (%s_%s).",
185229
envPrefix, envDockerUsername,
186230
))
231+
_ = fs.MarkDeprecated("docker-username", "use keychain instead")
187232
fs.StringVar(&o.Client.Docker.Password,
188233
"docker-password", "",
189234
fmt.Sprintf(
190235
"Password to authenticate with docker registry (%s_%s).",
191236
envPrefix, envDockerPassword,
192237
))
238+
_ = fs.MarkDeprecated("docker-password", "use keychain instead")
193239
fs.StringVar(&o.Client.Docker.Token,
194240
"docker-token", "",
195241
fmt.Sprintf(
196242
"Token to authenticate with docker registry. Cannot be used with "+
197243
"username/password (%s_%s).",
198244
envPrefix, envDockerToken,
199245
))
246+
_ = fs.MarkDeprecated("docker-token", "use keychain instead")
200247
///
201248

202249
/// ECR
@@ -233,6 +280,7 @@ func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
233280
"Access token for read access to private GCR registries (%s_%s).",
234281
envPrefix, envGCRAccessToken,
235282
))
283+
_ = fs.MarkDeprecated("gcr-token", "use keychain instead")
236284
///
237285

238286
/// GHCR
@@ -242,6 +290,7 @@ func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
242290
"Personal Access token for read access to GHCR releases (%s_%s).",
243291
envPrefix, envGHCRAccessToken,
244292
))
293+
_ = fs.MarkDeprecated("gchr-token", "use keychain instead")
245294
fs.StringVar(&o.Client.GHCR.Hostname,
246295
"gchr-hostname", "",
247296
fmt.Sprintf(
@@ -257,6 +306,7 @@ func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
257306
"Access token for read access to private Quay registries (%s_%s).",
258307
envPrefix, envQuayToken,
259308
))
309+
_ = fs.MarkDeprecated("quay-token", "use keychain instead")
260310
///
261311

262312
/// Selfhosted
@@ -266,19 +316,22 @@ func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
266316
"Username is authenticate with a selfhosted registry (%s_%s_%s).",
267317
envPrefix, envSelfhostedPrefix, envSelfhostedUsername,
268318
))
319+
_ = fs.MarkDeprecated("selfhosted-username", "use keychain instead")
269320
fs.StringVar(&o.selfhosted.Password,
270321
"selfhosted-password", "",
271322
fmt.Sprintf(
272323
"Password is authenticate with a selfhosted registry (%s_%s_%s).",
273324
envPrefix, envSelfhostedPrefix, envSelfhostedPassword,
274325
))
326+
_ = fs.MarkDeprecated("selfhosted-password", "use keychain instead")
275327
fs.StringVar(&o.selfhosted.Bearer,
276328
"selfhosted-token", "",
277329
fmt.Sprintf(
278330
"Token to authenticate to a selfhosted registry. Cannot be used with "+
279331
"username/password (%s_%s_%s).",
280332
envPrefix, envSelfhostedPrefix, envSelfhostedBearer,
281333
))
334+
_ = fs.MarkDeprecated("selfhosted-token", "use keychain instead")
282335
fs.StringVar(&o.selfhosted.TokenPath,
283336
"selfhosted-token-path", "",
284337
fmt.Sprintf(
@@ -305,12 +358,9 @@ func (o *Options) addAuthFlags(fs *pflag.FlagSet) {
305358
"THIS IS NOT RECOMMENDED AND IS INTENDED FOR DEBUGGING (%s_%s_%s)",
306359
envPrefix, envSelfhostedPrefix, envSelfhostedInsecure,
307360
))
308-
// if !validSelfHostedOpts(o) {
309-
// panic(fmt.Errorf("invalid self hosted configuration"))
310-
// }
311361
}
312362

313-
func (o *Options) complete() {
363+
func (o *Options) complete() error {
314364
o.Client.Selfhosted = make(map[string]*selfhosted.Options)
315365

316366
envs := os.Environ()
@@ -338,6 +388,9 @@ func (o *Options) complete() {
338388
{envGHCRHostname, &o.Client.GHCR.Hostname},
339389

340390
{envQuayToken, &o.Client.Quay.Token},
391+
392+
{envKeychainNamespace, &o.Client.KeyChain.Namespace},
393+
{envKeychainServiceAccountName, &o.Client.KeyChain.ServiceAccountName},
341394
} {
342395
for _, env := range envs {
343396
if o.assignEnv(env, opt.key, opt.assign) {
@@ -346,7 +399,7 @@ func (o *Options) complete() {
346399
}
347400
}
348401

349-
o.assignSelfhosted(envs)
402+
return o.assignSelfhosted(envs)
350403
}
351404

352405
func (o *Options) assignEnv(env, key string, assign *string) bool {
@@ -363,7 +416,24 @@ func (o *Options) assignEnv(env, key string, assign *string) bool {
363416
return false
364417
}
365418

366-
func (o *Options) assignSelfhosted(envs []string) {
419+
// assignSelfhosted processes a list of environment variables and assigns
420+
// self-hosted configuration options to the Options struct. It parses the
421+
// environment variables using predefined regular expressions to extract
422+
// self-hosted configuration details such as token path, bearer token, host,
423+
// username, password, insecure flag, and CA path.
424+
//
425+
// The function ensures that each self-hosted configuration is initialized
426+
// before assigning values. It also validates the self-hosted options after
427+
// processing all environment variables.
428+
//
429+
// Parameters:
430+
// - envs: A slice of strings representing environment variables in the
431+
// format "KEY=VALUE".
432+
//
433+
// Returns:
434+
// - error: An error if validation of the self-hosted options fails, or nil
435+
// if the operation is successful.
436+
func (o *Options) assignSelfhosted(envs []string) error {
367437
if o.Client.Selfhosted == nil {
368438
o.Client.Selfhosted = make(map[string]*selfhosted.Options)
369439
}
@@ -451,26 +521,40 @@ func (o *Options) assignSelfhosted(envs []string) {
451521
o.Client.Selfhosted[o.selfhosted.Host] = &o.selfhosted
452522
}
453523

454-
if !validSelfHostedOpts(o) {
455-
panic(fmt.Errorf("invalid self hosted configuration"))
456-
}
524+
return validateSelfHostedOpts(o)
457525
}
458526

459-
func validSelfHostedOpts(opts *Options) bool {
527+
// validateSelfHostedOpts validates the self-hosted options provided in the
528+
// Options struct. It checks both the options set using environment variables
529+
// and those set using flags.
530+
//
531+
// For options set using environment variables, it iterates through the list
532+
// of self-hosted options and ensures that each host is valid.
533+
//
534+
// For options set using flags, it validates the host in the selfhosted.Options
535+
// struct.
536+
//
537+
// Returns an error if any of the self-hosted options contain an invalid host,
538+
// otherwise returns nil.
539+
func validateSelfHostedOpts(opts *Options) error {
460540
// opts set using env vars
461541
if opts.Client.Selfhosted != nil {
462-
for _, selfHostedOpts := range opts.Client.Selfhosted {
463-
return isValidOption(selfHostedOpts.Host, "")
542+
for name, selfHostedOpts := range opts.Client.Selfhosted {
543+
if err := isValidOption(selfHostedOpts.Host, ""); !err {
544+
return fmt.Errorf("invalid self-hosted option for: %s", name)
545+
}
464546
}
465547
}
466548

467549
// opts set using flags
468550
if opts.selfhosted != (selfhosted.Options{}) {
469-
return isValidOption(opts.selfhosted.Host, "")
551+
if !isValidOption(opts.selfhosted.Host, "") {
552+
return fmt.Errorf("invalid self-hosted option for host: %s", opts.selfhosted.Host)
553+
}
470554
}
471-
return true
555+
return nil
472556
}
473557

474-
func isValidOption(option, invalid string) bool {
558+
func isValidOption(option, invalid any) bool {
475559
return option != invalid
476560
}

0 commit comments

Comments
 (0)