-
Notifications
You must be signed in to change notification settings - Fork 153
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The command validates a given OIDC configuration, either from a referenced Secret or from CLI flags. This will help users debug issues with Weave GitOps OIDC configuration as well as provide a way to validate a configuration before putting it on a cluster. The command consumes OIDC configuration from CLI flags or from a Secret on a cluster and sends the user through an OIDC authorization code flow. If it succeeds, the username and groups claims are logged to stdout. The command validates the Secret for missing fields and also prints all errors returned from the OIDC provider so that users know what went wrong. This will work out of the box with OIDC providers given they are configured to accept "http://localhost:9876" as a redirect URI.
- Loading branch information
Max Jonas Werner
committed
Nov 24, 2023
1 parent
6095bdb
commit d1e9c95
Showing
13 changed files
with
1,156 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package oidcconfig | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"github.com/spf13/cobra" | ||
"k8s.io/cli-runtime/pkg/genericclioptions" | ||
|
||
"github.com/weaveworks/weave-gitops/cmd/gitops/cmderrors" | ||
"github.com/weaveworks/weave-gitops/cmd/gitops/config" | ||
"github.com/weaveworks/weave-gitops/pkg/logger" | ||
"github.com/weaveworks/weave-gitops/pkg/oidc/check" | ||
"github.com/weaveworks/weave-gitops/pkg/run" | ||
"github.com/weaveworks/weave-gitops/pkg/server/auth" | ||
) | ||
|
||
func OIDCConfigCommand(opts *config.Options) *cobra.Command { | ||
var ( | ||
kubeConfigArgs *genericclioptions.ConfigFlags | ||
fromSecretFlag string | ||
skipSecretFlag bool | ||
clientIDFlag string | ||
clientSecretFlag string | ||
scopesFlag []string | ||
claimUsernameFlag string | ||
issuerURLFlag string | ||
) | ||
|
||
cmd := &cobra.Command{ | ||
Use: "oidc-config", | ||
Short: "Check an OIDC configuration for proper functionality.", | ||
Long: "This command will send the user through an OIDC authorization code flow " + | ||
"using the given OIDC configuration. This is helpful for verifying that a given " + | ||
"configuration will work properly with Weave GitOps or for debugging issues. " + | ||
"Without any provided flags it will read the configuration from a Secret" + | ||
"on the cluster.", | ||
Example: ` | ||
# Check the OIDC configuration stored in the flux-system/oidc-auth Secret | ||
gitops check oidc-config | ||
# Check a different set of scopes | ||
gitops check oidc-config --scopes=openid,groups | ||
# Check a different username cliam | ||
gitops check oidc-config --claim-username=sub | ||
# Check configuration without fetching a Secret from the cluster | ||
gitops check oidc-config --skip-secret --client-id=CID --client-secret=SEC --issuer-url=https://example.org | ||
`, | ||
SilenceUsage: true, | ||
SilenceErrors: true, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if skipSecretFlag { | ||
fromSecretFlag = "" // the skip flag overrides this one. | ||
} | ||
|
||
cfg, err := kubeConfigArgs.ToRESTConfig() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if fromSecretFlag == "" { | ||
if clientIDFlag == "" || | ||
clientSecretFlag == "" || | ||
issuerURLFlag == "" { | ||
return fmt.Errorf("when not reading OIDC configuration from a Secret, you need to provide " + | ||
"client ID, client secret and issuer URL using the respective command-line flags") | ||
} | ||
} | ||
|
||
log := logger.NewCLILogger(os.Stdout) | ||
kubeClient, err := run.GetKubeClient(log, *kubeConfigArgs.Context, cfg, nil) | ||
if err != nil { | ||
return cmderrors.ErrGetKubeClient | ||
} | ||
|
||
ns, err := cmd.Flags().GetString("namespace") | ||
if err != nil { | ||
return fmt.Errorf("failed getting namespace flag: %w", err) | ||
} | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) | ||
defer cancel() | ||
claims, err := check.GetClaims(ctx, check.Options{ | ||
ClientID: clientIDFlag, | ||
ClientSecret: clientSecretFlag, | ||
IssuerURL: issuerURLFlag, | ||
SecretName: fromSecretFlag, | ||
SecretNamespace: ns, | ||
Scopes: scopesFlag, | ||
ClaimUsername: claimUsernameFlag, | ||
}, log, kubeClient) | ||
|
||
if err != nil { | ||
return fmt.Errorf("failed getting claims: %w", err) | ||
} | ||
|
||
log.Println("user: %s", claims.Username) | ||
if len(claims.Groups) != 0 { | ||
log.Println("groups: %s", strings.Join(claims.Groups, ", ")) | ||
} else { | ||
log.Println("no groups claim") | ||
} | ||
|
||
return nil | ||
}, | ||
DisableAutoGenTag: true, | ||
} | ||
|
||
kubeConfigArgs = run.GetKubeConfigArgs() | ||
kubeConfigArgs.AddFlags(cmd.Flags()) | ||
|
||
cmd.Flags().StringVar(&clientIDFlag, "client-id", "", "OIDC client ID") | ||
cmd.Flags().StringVar(&clientSecretFlag, "client-secret", "", "OIDC client secret") | ||
cmd.Flags().StringVar(&issuerURLFlag, "issuer-url", "", "OIDC issuer URL") | ||
cmd.Flags().StringVar(&fromSecretFlag, "from-secret", "oidc-auth", "Get OIDC configuration from the given Secret resource") | ||
cmd.Flags().BoolVar(&skipSecretFlag, "skip-secret", false, | ||
"Do not read OIDC configuration from a Kubernetes Secret but rely solely on the values from the given flags.") | ||
cmd.Flags().StringVar(&claimUsernameFlag, "claim-username", "", "ID token claim to use as the user name.") | ||
cmd.Flags().StringSliceVar(&scopesFlag, "scopes", nil, fmt.Sprintf("OIDC scopes to request (default [%s])", strings.Join(auth.DefaultScopes, ","))) | ||
|
||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.