diff --git a/cmd/argocd-dex/commands/argocd_dex.go b/cmd/argocd-dex/commands/argocd_dex.go index 42bf038db722f..7d9f04c31f553 100644 --- a/cmd/argocd-dex/commands/argocd_dex.go +++ b/cmd/argocd-dex/commands/argocd_dex.go @@ -17,8 +17,10 @@ import ( cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/util/cli" "github.com/argoproj/argo-cd/v2/util/dex" + "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/settings" + "github.com/argoproj/argo-cd/v2/util/tls" ) const ( @@ -44,6 +46,7 @@ func NewCommand() *cobra.Command { func NewRunDexCommand() *cobra.Command { var ( clientConfig clientcmd.ClientConfig + disableTLS bool ) var command = cobra.Command{ Use: "rundex", @@ -70,6 +73,22 @@ func NewRunDexCommand() *cobra.Command { config.UserAgent = fmt.Sprintf("argocd-dex/%s (%s)", vers.Version, vers.Platform) kubeClientset := kubernetes.NewForConfigOrDie(config) + if !disableTLS { + config, err := tls.CreateServerTLSConfig("/tls/tls.crt", "/tls/tls.key", []string{"localhost", "dexserver"}) + if err != nil { + log.Fatalf("could not create TLS config: %v", err) + } + certPem, keyPem := tls.EncodeX509KeyPair(config.Certificates[0]) + err = os.WriteFile("/tmp/tls.crt", certPem, 0600) + if err != nil { + log.Fatalf("could not write TLS certificate: %v", err) + } + err = os.WriteFile("/tmp/tls.key", keyPem, 0600) + if err != nil { + log.Fatalf("could not write TLS key: %v", err) + } + } + settingsMgr := settings.NewSettingsManager(ctx, kubeClientset, namespace) prevSettings, err := settingsMgr.GetSettings() errors.CheckError(err) @@ -78,7 +97,7 @@ func NewRunDexCommand() *cobra.Command { for { var cmd *exec.Cmd - dexCfgBytes, err := dex.GenerateDexConfigYAML(prevSettings) + dexCfgBytes, err := dex.GenerateDexConfigYAML(prevSettings, disableTLS) errors.CheckError(err) if len(dexCfgBytes) == 0 { log.Infof("dex is not configured") @@ -96,7 +115,7 @@ func NewRunDexCommand() *cobra.Command { // loop until the dex config changes for { newSettings := <-updateCh - newDexCfgBytes, err := dex.GenerateDexConfigYAML(newSettings) + newDexCfgBytes, err := dex.GenerateDexConfigYAML(newSettings, disableTLS) errors.CheckError(err) if string(newDexCfgBytes) != string(dexCfgBytes) { prevSettings = newSettings @@ -119,6 +138,7 @@ func NewRunDexCommand() *cobra.Command { clientConfig = cli.AddKubectlFlagsToCmd(&command) command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json") command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error") + command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_DEX_SERVER_DISABLE_TLS", false), "Disable TLS on the HTTP endpoint") return &command } @@ -126,6 +146,7 @@ func NewGenDexConfigCommand() *cobra.Command { var ( clientConfig clientcmd.ClientConfig out string + disableTLS bool ) var command = cobra.Command{ Use: "gendexcfg", @@ -135,6 +156,7 @@ func NewGenDexConfigCommand() *cobra.Command { cli.SetLogFormat(cmdutil.LogFormat) cli.SetLogLevel(cmdutil.LogLevel) + config, err := clientConfig.ClientConfig() errors.CheckError(err) namespace, _, err := clientConfig.Namespace() @@ -143,7 +165,7 @@ func NewGenDexConfigCommand() *cobra.Command { settingsMgr := settings.NewSettingsManager(ctx, kubeClientset, namespace) settings, err := settingsMgr.GetSettings() errors.CheckError(err) - dexCfgBytes, err := dex.GenerateDexConfigYAML(settings) + dexCfgBytes, err := dex.GenerateDexConfigYAML(settings, disableTLS) errors.CheckError(err) if len(dexCfgBytes) == 0 { log.Infof("dex is not configured") @@ -185,6 +207,7 @@ func NewGenDexConfigCommand() *cobra.Command { command.Flags().StringVar(&cmdutil.LogFormat, "logformat", "text", "Set the logging format. One of: text|json") command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error") command.Flags().StringVarP(&out, "out", "o", "", "Output to the specified file instead of stdout") + command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_DEX_SERVER_DISABLE_TLS", false), "Disable TLS on the HTTP endpoint") return &command } diff --git a/cmd/argocd-server/commands/argocd_server.go b/cmd/argocd-server/commands/argocd_server.go index af85230870747..df838c4d1cbb7 100644 --- a/cmd/argocd-server/commands/argocd_server.go +++ b/cmd/argocd-server/commands/argocd_server.go @@ -21,6 +21,7 @@ import ( "github.com/argoproj/argo-cd/v2/server" servercache "github.com/argoproj/argo-cd/v2/server/cache" "github.com/argoproj/argo-cd/v2/util/cli" + "github.com/argoproj/argo-cd/v2/util/dex" "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/kube" @@ -66,6 +67,8 @@ func NewCommand() *cobra.Command { contentSecurityPolicy string repoServerPlaintext bool repoServerStrictTLS bool + dexServerPlaintext bool + dexServerStrictTLS bool staticAssetsDir string ) var command = &cobra.Command{ @@ -129,6 +132,28 @@ func NewCommand() *cobra.Command { tlsConfig.Certificates = pool } + dexTlsConfig := &dex.DexTLSConfig{ + DisableTLS: dexServerPlaintext, + StrictValidation: dexServerStrictTLS, + } + + if !dexServerPlaintext && dexServerStrictTLS { + pool, err := tls.LoadX509CertPool( + fmt.Sprintf("%s/dex/tls/ca.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)), + ) + if err != nil { + log.Fatalf("%v", err) + } + dexTlsConfig.RootCAs = pool + cert, err := tls.LoadX509Cert( + fmt.Sprintf("%s/dex/tls/tls.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)), + ) + if err != nil { + log.Fatalf("%v", err) + } + dexTlsConfig.Certificate = cert.Raw + } + repoclientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds, tlsConfig) if rootPath != "" { if baseHRef != "" && baseHRef != rootPath { @@ -148,6 +173,7 @@ func NewCommand() *cobra.Command { AppClientset: appClientSet, RepoClientset: repoclientset, DexServerAddr: dexServerAddress, + DexTLSConfig: dexTlsConfig, DisableAuth: disableAuth, EnableGZip: enableGZip, TLSConfigCustomizer: tlsConfigCustomizer, @@ -204,6 +230,8 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&contentSecurityPolicy, "content-security-policy", env.StringFromEnv("ARGOCD_SERVER_CONTENT_SECURITY_POLICY", "frame-ancestors 'self';"), "Set Content-Security-Policy header in HTTP responses to `value`. To disable, set to \"\".") command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_SERVER_REPO_SERVER_PLAINTEXT", false), "Use a plaintext client (non-TLS) to connect to repository server") command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_REPO_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to repo server") + command.Flags().BoolVar(&dexServerPlaintext, "dex-server-plaintext", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_PLAINTEXT", false), "Use a plaintext client (non-TLS) to connect to dex server") + command.Flags().BoolVar(&dexServerStrictTLS, "dex-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to dex server") tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command) cacheSrc = servercache.AddCacheFlagsToCmd(command, func(client *redis.Client) { redisClient = client diff --git a/common/common.go b/common/common.go index ac5c4768903fc..f73927b6db932 100644 --- a/common/common.go +++ b/common/common.go @@ -14,7 +14,7 @@ const ( // DefaultRepoServerAddr is the gRPC address of the Argo CD repo server DefaultRepoServerAddr = "argocd-repo-server:8081" // DefaultDexServerAddr is the HTTP address of the Dex OIDC server, which we run a reverse proxy against - DefaultDexServerAddr = "http://argocd-dex-server:5556" + DefaultDexServerAddr = "argocd-dex-server:5556" // DefaultRedisAddr is the default redis address DefaultRedisAddr = "argocd-redis:6379" ) diff --git a/docs/operator-manual/argocd-cmd-params-cm.yaml b/docs/operator-manual/argocd-cmd-params-cm.yaml index c0ceee4c39e6d..0baac5326ec13 100644 --- a/docs/operator-manual/argocd-cmd-params-cm.yaml +++ b/docs/operator-manual/argocd-cmd-params-cm.yaml @@ -64,6 +64,10 @@ data: server.repo.server.plaintext: "false" # Perform strict validation of TLS certificates when connecting to repo server server.repo.server.strict.tls: "false" + # Use a plaintext client (non-TLS) to connect to dex server + server.dex.server.plaintext: "false" + # Perform strict validation of TLS certificates when connecting to dex server + server.dex.server.strict.tls: "false" # Disable client authentication server.disable.auth: "false" # Enable GZIP compression @@ -117,3 +121,6 @@ data: # Changing this to "true" will not allow _all_ out-of-bounds symlinks. Those will still be blocked for things like values # files in Helm charts. But symlinks which are not explicitly blocked by other checks will be allowed. reposerver.allow.oob.symlinks: "false" + + # Disable TLS on the HTTP endpoint + dexserver.disable.tls: "false" diff --git a/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md b/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md index 8080377192853..f557df7889c80 100644 --- a/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md +++ b/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md @@ -17,6 +17,7 @@ argocd-dex gendexcfg [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-tls Disable TLS on the HTTP endpoint -h, --help help for gendexcfg --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/operator-manual/server-commands/argocd-dex_rundex.md b/docs/operator-manual/server-commands/argocd-dex_rundex.md index fae4fa08bf3c2..39695d80fbd53 100644 --- a/docs/operator-manual/server-commands/argocd-dex_rundex.md +++ b/docs/operator-manual/server-commands/argocd-dex_rundex.md @@ -17,6 +17,7 @@ argocd-dex rundex [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-tls Disable TLS on the HTTP endpoint -h, --help help for rundex --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/operator-manual/server-commands/argocd-server.md b/docs/operator-manual/server-commands/argocd-server.md index fbee0b86a0ffb..43ab727a47651 100644 --- a/docs/operator-manual/server-commands/argocd-server.md +++ b/docs/operator-manual/server-commands/argocd-server.md @@ -26,7 +26,9 @@ argocd-server [flags] --content-security-policy value Set Content-Security-Policy header in HTTP responses to value. To disable, set to "". (default "frame-ancestors 'self';") --context string The name of the kubeconfig context to use --default-cache-expiration duration Cache expiration default (default 24h0m0s) - --dex-server string Dex server address (default "http://argocd-dex-server:5556") + --dex-server string Dex server address (default "argocd-dex-server:5556") + --dex-server-plaintext Use a plaintext client (non-TLS) to connect to dex server + --dex-server-strict-tls Perform strict validation of TLS certificates when connecting to dex server --disable-auth Disable client authentication --enable-gzip Enable GZIP compression --gloglevel int Set the glog logging level diff --git a/docs/operator-manual/tls.md b/docs/operator-manual/tls.md index bd014fa6d6588..a9881604c1a37 100644 --- a/docs/operator-manual/tls.md +++ b/docs/operator-manual/tls.md @@ -1,14 +1,16 @@ # TLS configuration -Argo CD provides two inbound TLS endpoints that can be configured: +Argo CD provides three inbound TLS endpoints that can be configured: * The user-facing endpoint of the `argocd-server` workload which serves the UI and the API * The endpoint of the `argocd-repo-server`, which is accessed by `argocd-server` and `argocd-application-controller` workloads to request repository operations. +* The endpoint of the `argocd-dex-server`, which is accessed by `argocd-server` + to handle OIDC authentication. -By default, and without further configuration, both of these endpoints will be +By default, and without further configuration, these endpoints will be set-up to use an automatically generated, self-signed certificate. However, most users will want to explicitly configure the certificates for these TLS endpoints, possibly using automated means such as `cert-manager` or using @@ -99,6 +101,9 @@ kubectl create -n argocd secret tls argocd-repo-server-tls \ --key=/path/to/key.pem ``` +If the certificate is self-signed, you will also need to add `ca.crt` to the secret +with the contents of your CA certificate. + Please note, that as opposed to `argocd-server`, the `argocd-repo-server` is not able to pick up changes to this secret automatically. If you create (or update) this secret, the `argocd-repo-server` pods need to be restarted. @@ -108,6 +113,45 @@ for the `argocd-repo-server`, containing at least the entries for `DNS:argocd-repo-server` and `DNS:argocd-repo-server.argo-cd.svc` depending on how your workloads connect to the repository server. +## Configuring inbound TLS for argocd-dex-server > v2.5 + +### Inbound TLS options for argocd-dex-server + +You can configure certain TLS options for the `argocd-dex-server` workload by +setting command line parameters. The following parameters are available: + +|Parameter|Default|Description| +|---------|-------|-----------| +|`--disable-tls`|`false`|Disables TLS completely| + +### Inbound TLS certificates used by argocd-dex-server + +To configure the TLS certificate used by the `argocd-dex-server` workload, +create a secret named `argocd-dex-server-tls` in the namespace where Argo CD +is running in with the certificate's key pair stored in `tls.crt` and +`tls.key` keys. If this secret does not exist, `argocd-dex-server` will +generate and use a self-signed certificate. + +To create this secret, you can use `kubectl`: + +```shell +kubectl create -n argocd secret tls argocd-dex-server-tls \ + --cert=/path/to/cert.pem \ + --key=/path/to/key.pem +``` + +If the certificate is self-signed, you will also need to add `ca.crt` to the secret +with the contents of your CA certificate. + +Please note, that as opposed to `argocd-server`, the `argocd-dex-server` is +not able to pick up changes to this secret automatically. If you create (or +update) this secret, the `argocd-dex-server` pods need to be restarted. + +Also note, that the certificate should be issued with the correct SAN entries +for the `argocd-dex-server`, containing at least the entries for +`DNS:argocd-dex-server` and `DNS:argocd-dex-server.argo-cd.svc` depending +on how your workloads connect to the repository server. + ## Configuring TLS between Argo CD components ### Configuring TLS to argocd-repo-server @@ -136,6 +180,35 @@ The `argocd-server` and `argocd-application-controller` workloads will now validate the TLS certificate of the `argocd-repo-server` by using the certificate stored in the `argocd-repo-server-tls` secret. +!!!note "Certificate expiry" + Please make sure that the certificate has a proper life time. Keep in + mind that when you have to replace the certificate, all workloads have + to be restarted in order to properly work again. + +### Configuring TLS to argocd-dex-server > v2.5 + +`argocd-server` communicates with the `argocd-dex-server` using an HTTPS API +over TLS. By default, `argocd-dex-server` generates a non-persistent, self +signed certificate to use for its HTTPS endpoint on startup. Because the +`argocd-dex-server` has no means to connect to the K8s control plane API, +this certificate is not being available to outside consumers for verification. +The `argocd-server` will use a non-validating connection to the `argocd-dex-server` +for this reason. + +To change this behavior to be more secure by having the `argocd-server` validate +the TLS certificate of the `argocd-dex-server` endpoint, the following steps need +to be performed: + +* Create a persistent TLS certificate to be used by `argocd-dex-server`, as + shown above +* Restart the `argocd-dex-server` pod(s) +* Modify the pod startup parameters for `argocd-server` to include the +`--dex-server-strict-tls` parameter. + +The `argocd-server` workload will now validate the TLS certificate of the +`argocd-dex-server` by using the certificate stored in the `argocd-dex-server-tls` +secret. + !!!note "Certificate expiry" Please make sure that the certificate has a proper life time. Keep in mind that when you have to replace the certificate, all workloads have @@ -162,3 +235,24 @@ In this case, you will need to: After this change, the `argocd-server` and `argocd-application-controller` will use a plain text connection to the side-car proxy, that will handle all aspects of TLS to the `argocd-repo-server`'s TLS side-car proxy. + +### Disabling TLS to argocd-dex-server + +In some scenarios where mTLS through side-car proxies is involved (e.g. +in a service mesh), you may want configure the connections between +`argocd-server` to `argocd-dex-server` to not use TLS at all. + +In this case, you will need to: + +* Configure `argocd-dex-server` with TLS on the HTTPS API disabled by specifying + the `--disable-tls` parameter to the pod container's startup arguments +* Configure `argocd-server` to not use TLS for connections to the `argocd-dex-server` + by specifying the parameter `--dex-server-plaintext` to the pod container's startup + arguments +* Configure `argocd-server` to connect to the side-car instead of directly to the + `argocd-dex-server` service by specifying its address via the `--dex-server
` + parameter + +After this change, the `argocd-server` will use a plain text connection to the side-car +proxy, that will handle all aspects of TLS to the `argocd-dex-server`'s TLS side-car proxy. + diff --git a/docs/operator-manual/upgrading/2.4-2.5.md b/docs/operator-manual/upgrading/2.4-2.5.md index a10d5dc64462d..a0e7cf5bf2680 100644 --- a/docs/operator-manual/upgrading/2.4-2.5.md +++ b/docs/operator-manual/upgrading/2.4-2.5.md @@ -1,5 +1,12 @@ # v2.4 to 2.5 +## Dex server TLS configuration + +In order to secure the communications between the dex server and the Argo CD API server, TLS is now enabled by default on the dex server. + +By default, without configuration, the dex server will generate a self-signed certificate upon startup. However, we recommend that users +configure their own TLS certificate using the `argocd-dex-server-tls` secret. Please refer to the [TLS configuration guide](../tls.md#configuring-tls-to-argocd-dex-server) for more information. + ## Out-of-bounds symlinks now blocked at fetch There have been several path traversal and identification vulnerabilities disclosed in the past related to symlinks. To help prevent any further vulnerabilities, we now scan all repositories and Helm charts for **out of bounds symlinks** at the time they are fetched and block further processing if they are found. diff --git a/manifests/base/dex/argocd-dex-server-deployment.yaml b/manifests/base/dex/argocd-dex-server-deployment.yaml index ae227f172d4ce..23d8bd07b961e 100644 --- a/manifests/base/dex/argocd-dex-server-deployment.yaml +++ b/manifests/base/dex/argocd-dex-server-deployment.yaml @@ -40,6 +40,13 @@ spec: image: ghcr.io/dexidp/dex:v2.30.2 imagePullPolicy: Always command: [/shared/argocd-dex, rundex] + env: + - name: ARGOCD_DEX_SERVER_DISABLE_TLS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: dexserver.disable.tls + optional: true securityContext: capabilities: drop: @@ -58,11 +65,24 @@ spec: name: static-files - mountPath: /tmp name: dexconfig + - mountPath: /tls + name: argocd-dex-server-tls volumes: - emptyDir: {} name: static-files - emptyDir: {} name: dexconfig + - name: argocd-dex-server-tls + secret: + secretName: argocd-dex-server-tls + optional: true + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: diff --git a/manifests/base/server/argocd-server-deployment.yaml b/manifests/base/server/argocd-server-deployment.yaml index dd7512ad12521..2808f0d88b689 100644 --- a/manifests/base/server/argocd-server-deployment.yaml +++ b/manifests/base/server/argocd-server-deployment.yaml @@ -106,6 +106,18 @@ spec: name: argocd-cmd-params-cm key: server.repo.server.strict.tls optional: true + - name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.dex.server.plaintext + optional: true + - name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.dex.server.strict.tls + optional: true - name: ARGOCD_TLS_MIN_VERSION valueFrom: configMapKeyRef: @@ -191,6 +203,8 @@ spec: mountPath: /app/config/tls - name: argocd-repo-server-tls mountPath: /app/config/server/tls + - name: argocd-dex-server-tls + mountPath: /app/config/dex/tls - mountPath: /home/argocd name: plugins-home - mountPath: /tmp @@ -241,6 +255,15 @@ spec: path: tls.key - key: ca.crt path: ca.crt + - name: argocd-dex-server-tls + secret: + secretName: argocd-dex-server-tls + optional: true + items: + - key: tls.crt + path: tls.crt + - key: ca.crt + path: ca.crt affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index dcf15d184f6f1..da54f3cffbc8f 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -10548,6 +10548,13 @@ spec: - command: - /shared/argocd-dex - rundex + env: + - name: ARGOCD_DEX_SERVER_DISABLE_TLS + valueFrom: + configMapKeyRef: + key: dexserver.disable.tls + name: argocd-cmd-params-cm + optional: true image: ghcr.io/dexidp/dex:v2.30.2 imagePullPolicy: Always name: dex @@ -10569,6 +10576,8 @@ spec: name: static-files - mountPath: /tmp name: dexconfig + - mountPath: /tls + name: argocd-dex-server-tls initContainers: - command: - cp @@ -10598,6 +10607,17 @@ spec: name: static-files - emptyDir: {} name: dexconfig + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -11104,6 +11124,18 @@ spec: key: server.repo.server.strict.tls name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: server.dex.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: server.dex.server.strict.tls + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_TLS_MIN_VERSION valueFrom: configMapKeyRef: @@ -11216,6 +11248,8 @@ spec: name: tls-certs - mountPath: /app/config/server/tls name: argocd-repo-server-tls + - mountPath: /app/config/dex/tls + name: argocd-dex-server-tls - mountPath: /home/argocd name: plugins-home - mountPath: /tmp @@ -11243,6 +11277,15 @@ spec: path: ca.crt optional: true secretName: argocd-repo-server-tls + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: StatefulSet diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml index c5260887e3575..6cf11342b1c82 100644 --- a/manifests/ha/namespace-install.yaml +++ b/manifests/ha/namespace-install.yaml @@ -1322,6 +1322,13 @@ spec: - command: - /shared/argocd-dex - rundex + env: + - name: ARGOCD_DEX_SERVER_DISABLE_TLS + valueFrom: + configMapKeyRef: + key: dexserver.disable.tls + name: argocd-cmd-params-cm + optional: true image: ghcr.io/dexidp/dex:v2.30.2 imagePullPolicy: Always name: dex @@ -1343,6 +1350,8 @@ spec: name: static-files - mountPath: /tmp name: dexconfig + - mountPath: /tls + name: argocd-dex-server-tls initContainers: - command: - cp @@ -1372,6 +1381,17 @@ spec: name: static-files - emptyDir: {} name: dexconfig + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -1878,6 +1898,18 @@ spec: key: server.repo.server.strict.tls name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: server.dex.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: server.dex.server.strict.tls + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_TLS_MIN_VERSION valueFrom: configMapKeyRef: @@ -1990,6 +2022,8 @@ spec: name: tls-certs - mountPath: /app/config/server/tls name: argocd-repo-server-tls + - mountPath: /app/config/dex/tls + name: argocd-dex-server-tls - mountPath: /home/argocd name: plugins-home - mountPath: /tmp @@ -2017,6 +2051,15 @@ spec: path: ca.crt optional: true secretName: argocd-repo-server-tls + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: StatefulSet diff --git a/manifests/install.yaml b/manifests/install.yaml index 82a3945c2679c..ccde214ab872b 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -9920,6 +9920,13 @@ spec: - command: - /shared/argocd-dex - rundex + env: + - name: ARGOCD_DEX_SERVER_DISABLE_TLS + valueFrom: + configMapKeyRef: + key: dexserver.disable.tls + name: argocd-cmd-params-cm + optional: true image: ghcr.io/dexidp/dex:v2.30.2 imagePullPolicy: Always name: dex @@ -9941,6 +9948,8 @@ spec: name: static-files - mountPath: /tmp name: dexconfig + - mountPath: /tls + name: argocd-dex-server-tls initContainers: - command: - cp @@ -9970,6 +9979,17 @@ spec: name: static-files - emptyDir: {} name: dexconfig + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -10442,6 +10462,18 @@ spec: key: server.repo.server.strict.tls name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: server.dex.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: server.dex.server.strict.tls + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_TLS_MIN_VERSION valueFrom: configMapKeyRef: @@ -10554,6 +10586,8 @@ spec: name: tls-certs - mountPath: /app/config/server/tls name: argocd-repo-server-tls + - mountPath: /app/config/dex/tls + name: argocd-dex-server-tls - mountPath: /home/argocd name: plugins-home - mountPath: /tmp @@ -10581,6 +10615,15 @@ spec: path: ca.crt optional: true secretName: argocd-repo-server-tls + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: StatefulSet diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 7e4caa4d2857c..892524680629e 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -694,6 +694,13 @@ spec: - command: - /shared/argocd-dex - rundex + env: + - name: ARGOCD_DEX_SERVER_DISABLE_TLS + valueFrom: + configMapKeyRef: + key: dexserver.disable.tls + name: argocd-cmd-params-cm + optional: true image: ghcr.io/dexidp/dex:v2.30.2 imagePullPolicy: Always name: dex @@ -715,6 +722,8 @@ spec: name: static-files - mountPath: /tmp name: dexconfig + - mountPath: /tls + name: argocd-dex-server-tls initContainers: - command: - cp @@ -744,6 +753,17 @@ spec: name: static-files - emptyDir: {} name: dexconfig + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -1216,6 +1236,18 @@ spec: key: server.repo.server.strict.tls name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: server.dex.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: server.dex.server.strict.tls + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_TLS_MIN_VERSION valueFrom: configMapKeyRef: @@ -1328,6 +1360,8 @@ spec: name: tls-certs - mountPath: /app/config/server/tls name: argocd-repo-server-tls + - mountPath: /app/config/dex/tls + name: argocd-dex-server-tls - mountPath: /home/argocd name: plugins-home - mountPath: /tmp @@ -1355,6 +1389,15 @@ spec: path: ca.crt optional: true secretName: argocd-repo-server-tls + - name: argocd-dex-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-dex-server-tls --- apiVersion: apps/v1 kind: StatefulSet diff --git a/server/account/account_test.go b/server/account/account_test.go index dae61d40d925c..d65c2e925b63d 100644 --- a/server/account/account_test.go +++ b/server/account/account_test.go @@ -64,7 +64,7 @@ func newTestAccountServerExt(ctx context.Context, enforceFn rbac.ClaimsEnforcerF } kubeclientset := fake.NewSimpleClientset(cm, secret) settingsMgr := settings.NewSettingsManager(ctx, kubeclientset, testNamespace) - sessionMgr := sessionutil.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", sessionutil.NewUserStateStorage(nil)) + sessionMgr := sessionutil.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, sessionutil.NewUserStateStorage(nil)) enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil) enforcer.SetClaimsEnforcerFunc(enforceFn) diff --git a/server/logout/logout_test.go b/server/logout/logout_test.go index 2c6c31a1b300f..692e741aa3c2f 100644 --- a/server/logout/logout_test.go +++ b/server/logout/logout_test.go @@ -213,7 +213,7 @@ func TestHandlerConstructLogoutURL(t *testing.T) { settingsManagerWithOIDCConfigButNoLogoutURL := settings.NewSettingsManager(context.Background(), kubeClientWithOIDCConfigButNoLogoutURL, "default") settingsManagerWithOIDCConfigButNoURL := settings.NewSettingsManager(context.Background(), kubeClientWithOIDCConfigButNoURL, "default") - sessionManager := session.NewSessionManager(settingsManagerWithOIDCConfig, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionManager := session.NewSessionManager(settingsManagerWithOIDCConfig, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) oidcHandler := NewHandler(appclientset.NewSimpleClientset(), settingsManagerWithOIDCConfig, sessionManager, rootPath, baseHRef, "default") oidcHandler.verifyToken = func(tokenString string) (jwt.Claims, string, error) { diff --git a/server/project/project_test.go b/server/project/project_test.go index 06b6b6659531f..00beec73c599b 100644 --- a/server/project/project_test.go +++ b/server/project/project_test.go @@ -84,7 +84,7 @@ func TestProjectServer(t *testing.T) { } t.Run("TestNormalizeProj", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projectWithRole := existingProj.DeepCopy() roleName := "roleName" role1 := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}} @@ -334,7 +334,7 @@ func TestProjectServer(t *testing.T) { id := "testId" t.Run("TestCreateTokenDenied", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projectWithRole := existingProj.DeepCopy() projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}} @@ -345,7 +345,7 @@ func TestProjectServer(t *testing.T) { }) t.Run("TestCreateTokenSuccessfullyUsingGroup", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projectWithRole := existingProj.DeepCopy() projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName, Groups: []string{"my-group"}}} argoDB := db.NewDB("default", settingsMgr, kubeclientset) @@ -361,7 +361,7 @@ func TestProjectServer(t *testing.T) { projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}} clientset := apps.NewSimpleClientset(projectWithRole) - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", nil, session.NewUserStateStorage(nil)) argoDB := db.NewDB("default", settingsMgr, kubeclientset) projectServer := NewServer("default", fake.NewSimpleClientset(), clientset, enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB) tokenResponse, err := projectServer.CreateToken(context.Background(), &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 100}) @@ -382,7 +382,7 @@ func TestProjectServer(t *testing.T) { projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}} clientset := apps.NewSimpleClientset(projectWithRole) - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", nil, session.NewUserStateStorage(nil)) argoDB := db.NewDB("default", settingsMgr, kubeclientset) projectServer := NewServer("default", fake.NewSimpleClientset(), clientset, enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB) tokenResponse, err := projectServer.CreateToken(context.Background(), &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1, Id: id}) @@ -403,7 +403,7 @@ func TestProjectServer(t *testing.T) { projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}} clientset := apps.NewSimpleClientset(projectWithRole) - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjListerFromInterface(clientset.ArgoprojV1alpha1().AppProjects("default")), "", nil, session.NewUserStateStorage(nil)) argoDB := db.NewDB("default", settingsMgr, kubeclientset) projectServer := NewServer("default", fake.NewSimpleClientset(), clientset, enforcer, sync.NewKeyLock(), sessionMgr, policyEnf, projInformer, settingsMgr, argoDB) tokenResponse, err := projectServer.CreateToken(context.Background(), &project.ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1, Id: id}) @@ -427,7 +427,7 @@ func TestProjectServer(t *testing.T) { _ = enforcer.SetBuiltinPolicy(`p, *, *, *, *, deny`) t.Run("TestDeleteTokenDenied", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projWithToken := existingProj.DeepCopy() issuedAt := int64(1) secondIssuedAt := issuedAt + 1 @@ -440,7 +440,7 @@ func TestProjectServer(t *testing.T) { }) t.Run("TestDeleteTokenSuccessfullyWithGroup", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projWithToken := existingProj.DeepCopy() issuedAt := int64(1) secondIssuedAt := issuedAt + 1 @@ -456,7 +456,7 @@ func TestProjectServer(t *testing.T) { p, role:admin, projects, update, *, allow`) t.Run("TestDeleteTokenSuccessfully", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projWithToken := existingProj.DeepCopy() issuedAt := int64(1) secondIssuedAt := issuedAt + 1 @@ -477,7 +477,7 @@ p, role:admin, projects, update, *, allow`) p, role:admin, projects, update, *, allow`) t.Run("TestDeleteTokenByIdSuccessfully", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projWithToken := existingProj.DeepCopy() issuedAt := int64(1) secondIssuedAt := issuedAt + 1 @@ -500,7 +500,7 @@ p, role:admin, projects, update, *, allow`) enforcer = newEnforcer(kubeclientset) t.Run("TestCreateTwoTokensInRoleSuccess", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projWithToken := existingProj.DeepCopy() tokenName := "testToken" token := v1alpha1.ProjectRole{Name: tokenName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}} @@ -666,7 +666,7 @@ p, role:admin, projects, update, *, allow`) }) t.Run("TestSyncWindowsActive", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projectWithSyncWindows := existingProj.DeepCopy() projectWithSyncWindows.Spec.SyncWindows = v1alpha1.SyncWindows{} win := &v1alpha1.SyncWindow{Kind: "allow", Schedule: "* * * * *", Duration: "1h"} @@ -679,7 +679,7 @@ p, role:admin, projects, update, *, allow`) }) t.Run("TestGetSyncWindowsStateCannotGetProjectDetails", func(t *testing.T) { - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projectWithSyncWindows := existingProj.DeepCopy() projectWithSyncWindows.Spec.SyncWindows = v1alpha1.SyncWindows{} win := &v1alpha1.SyncWindow{Kind: "allow", Schedule: "* * * * *", Duration: "1h"} @@ -698,7 +698,7 @@ p, role:admin, projects, update, *, allow`) // nolint:staticcheck ctx := context.WithValue(context.Background(), "claims", &jwt.MapClaims{"groups": []string{"my-group"}}) - sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", session.NewUserStateStorage(nil)) + sessionMgr := session.NewSessionManager(settingsMgr, test.NewFakeProjLister(), "", nil, session.NewUserStateStorage(nil)) projectWithSyncWindows := existingProj.DeepCopy() win := &v1alpha1.SyncWindow{Kind: "allow", Schedule: "* * * * *", Duration: "1h"} projectWithSyncWindows.Spec.SyncWindows = append(projectWithSyncWindows.Spec.SyncWindows, win) diff --git a/server/server.go b/server/server.go index 96be89078ddd2..72367b0874498 100644 --- a/server/server.go +++ b/server/server.go @@ -188,6 +188,7 @@ type ArgoCDServerOpts struct { MetricsPort int Namespace string DexServerAddr string + DexTLSConfig *dex.DexTLSConfig BaseHRef string RootPath string KubeClientset kubernetes.Interface @@ -238,7 +239,7 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer { appLister := factory.Argoproj().V1alpha1().Applications().Lister().Applications(opts.Namespace) userStateStorage := util_session.NewUserStateStorage(opts.RedisClient) - sessionMgr := util_session.NewSessionManager(settingsMgr, projLister, opts.DexServerAddr, userStateStorage) + sessionMgr := util_session.NewSessionManager(settingsMgr, projLister, opts.DexServerAddr, opts.DexTLSConfig, userStateStorage) enf := rbac.NewEnforcer(opts.KubeClientset, opts.Namespace, common.ArgoCDRBACConfigMapName, nil) enf.EnableEnforce(!opts.DisableAuth) err = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV) @@ -510,7 +511,7 @@ func (a *ArgoCDServer) watchSettings() { prevURL := a.settings.URL prevOIDCConfig := a.settings.OIDCConfig() - prevDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings) + prevDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings, a.DexTLSConfig == nil || a.DexTLSConfig.DisableTLS) errors.CheckError(err) prevGitHubSecret := a.settings.WebhookGitHubSecret prevGitLabSecret := a.settings.WebhookGitLabSecret @@ -525,7 +526,7 @@ func (a *ArgoCDServer) watchSettings() { for { newSettings := <-updateCh a.settings = newSettings - newDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings) + newDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings, a.DexTLSConfig == nil || a.DexTLSConfig.DisableTLS) errors.CheckError(err) if string(newDexCfgBytes) != string(prevDexCfgBytes) { log.Infof("dex config modified. restarting") @@ -938,12 +939,8 @@ func (a *ArgoCDServer) registerDexHandlers(mux *http.ServeMux) { } // Run dex OpenID Connect Identity Provider behind a reverse proxy (served at /api/dex) var err error - mux.HandleFunc(common.DexAPIEndpoint+"/", dexutil.NewDexHTTPReverseProxy(a.DexServerAddr, a.BaseHRef)) - if a.useTLS() { - tlsConfig := a.settings.TLSConfig() - tlsConfig.InsecureSkipVerify = true - } - a.ssoClientApp, err = oidc.NewClientApp(a.settings, a.DexServerAddr, a.BaseHRef) + mux.HandleFunc(common.DexAPIEndpoint+"/", dexutil.NewDexHTTPReverseProxy(a.DexServerAddr, a.BaseHRef, a.DexTLSConfig)) + a.ssoClientApp, err = oidc.NewClientApp(a.settings, a.DexServerAddr, a.DexTLSConfig, a.BaseHRef) errors.CheckError(err) mux.HandleFunc(common.LoginEndpoint, a.ssoClientApp.HandleLogin) mux.HandleFunc(common.CallbackEndpoint, a.ssoClientApp.HandleCallback) diff --git a/util/dex/config.go b/util/dex/config.go index 2b2faf7fdf355..5d569713c4e2a 100644 --- a/util/dex/config.go +++ b/util/dex/config.go @@ -9,7 +9,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/settings" ) -func GenerateDexConfigYAML(settings *settings.ArgoCDSettings) ([]byte, error) { +func GenerateDexConfigYAML(settings *settings.ArgoCDSettings, disableTls bool) ([]byte, error) { if !settings.IsDexConfigured() { return nil, nil } @@ -26,9 +26,18 @@ func GenerateDexConfigYAML(settings *settings.ArgoCDSettings) ([]byte, error) { dexCfg["storage"] = map[string]interface{}{ "type": "memory", } - dexCfg["web"] = map[string]interface{}{ - "http": "0.0.0.0:5556", + if disableTls { + dexCfg["web"] = map[string]interface{}{ + "http": "0.0.0.0:5556", + } + } else { + dexCfg["web"] = map[string]interface{}{ + "https": "0.0.0.0:5556", + "tlsCert": "/tmp/tls.crt", + "tlsKey": "/tmp/tls.key", + } } + dexCfg["grpc"] = map[string]interface{}{ "addr": "0.0.0.0:5557", } diff --git a/util/dex/dex.go b/util/dex/dex.go index b0b817153d911..4b9cfbfc5ac72 100644 --- a/util/dex/dex.go +++ b/util/dex/dex.go @@ -2,6 +2,8 @@ package dex import ( "bytes" + "crypto/tls" + "crypto/x509" "fmt" "io" "net/http" @@ -9,6 +11,7 @@ import ( "net/url" "path" "strconv" + "strings" log "github.com/sirupsen/logrus" @@ -22,16 +25,54 @@ func decorateDirector(director func(req *http.Request), target *url.URL) func(re } } +type DexTLSConfig struct { + DisableTLS bool + StrictValidation bool + RootCAs *x509.CertPool + Certificate []byte +} + +func TLSConfig(tlsConfig *DexTLSConfig) *tls.Config { + if tlsConfig == nil || tlsConfig.DisableTLS { + return nil + } + if !tlsConfig.StrictValidation { + return &tls.Config{ + InsecureSkipVerify: true, + } + } + return &tls.Config{ + InsecureSkipVerify: false, + RootCAs: tlsConfig.RootCAs, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if !bytes.Equal(rawCerts[0], tlsConfig.Certificate) { + return fmt.Errorf("dex server certificate does not match") + } + return nil + }, + } +} + // NewDexHTTPReverseProxy returns a reverse proxy to the Dex server. Dex is assumed to be configured // with the external issuer URL muxed to the same path configured in server.go. In other words, if // Argo CD API server wants to proxy requests at /api/dex, then the dex config yaml issuer URL should // also be /api/dex (e.g. issuer: https://argocd.example.com/api/dex) -func NewDexHTTPReverseProxy(serverAddr string, baseHRef string) func(writer http.ResponseWriter, request *http.Request) { - target, err := url.Parse(serverAddr) +func NewDexHTTPReverseProxy(serverAddr string, baseHRef string, tlsConfig *DexTLSConfig) func(writer http.ResponseWriter, request *http.Request) { + + fullAddr := DexServerAddressWithProtocol(serverAddr, tlsConfig) + + target, err := url.Parse(fullAddr) errors.CheckError(err) target.Path = baseHRef proxy := httputil.NewSingleHostReverseProxy(target) + + if tlsConfig != nil && !tlsConfig.DisableTLS { + proxy.Transport = &http.Transport{ + TLSClientConfig: TLSConfig(tlsConfig), + } + } + proxy.ModifyResponse = func(resp *http.Response) error { if resp.StatusCode == 500 { b, err := io.ReadAll(resp.Body) @@ -81,3 +122,15 @@ func (s DexRewriteURLRoundTripper) RoundTrip(r *http.Request) (*http.Response, e r.URL.Scheme = s.DexURL.Scheme return s.T.RoundTrip(r) } + +func DexServerAddressWithProtocol(orig string, tlsConfig *DexTLSConfig) string { + if strings.Contains(orig, "://") { + return orig + } else { + if tlsConfig == nil || tlsConfig.DisableTLS { + return "http://" + orig + } else { + return "https://" + orig + } + } +} diff --git a/util/dex/dex_test.go b/util/dex/dex_test.go index 026eb6caf5c6f..ef4d5305a723b 100644 --- a/util/dex/dex_test.go +++ b/util/dex/dex_test.go @@ -152,7 +152,7 @@ func Test_GenerateDexConfig(t *testing.T) { t.Run("Empty settings", func(t *testing.T) { s := settings.ArgoCDSettings{} - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.Nil(t, config) }) @@ -162,7 +162,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: invalidURL, DexConfig: goodDexConfig, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.Error(t, err) assert.Nil(t, config) }) @@ -172,7 +172,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: "", DexConfig: "invalidyaml", } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.Nil(t, config) }) @@ -182,7 +182,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: "http://localhost", DexConfig: "invalidyaml", } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.Nil(t, config) }) @@ -192,7 +192,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: "http://localhost", DexConfig: malformedDexConfig, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.Error(t, err) assert.Nil(t, config) }) @@ -202,7 +202,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: "http://localhost", DexConfig: badDexConfig, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.Error(t, err) assert.Nil(t, config) }) @@ -212,7 +212,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: "http://localhost", DexConfig: goodDexConfig, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.NotNil(t, config) }) @@ -223,7 +223,7 @@ func Test_GenerateDexConfig(t *testing.T) { DexConfig: goodDexConfig, Secrets: goodSecrets, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.NotNil(t, config) var dexCfg map[string]interface{} @@ -249,7 +249,7 @@ func Test_GenerateDexConfig(t *testing.T) { DexConfig: goodDexConfig, Secrets: goodSecretswithCRLF, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.NotNil(t, config) var dexCfg map[string]interface{} @@ -283,7 +283,7 @@ func Test_GenerateDexConfig(t *testing.T) { DexConfig: customStaticClientDexConfig, Secrets: goodSecretswithCRLF, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.NotNil(t, config) var dexCfg map[string]interface{} @@ -305,7 +305,7 @@ func Test_GenerateDexConfig(t *testing.T) { DexConfig: customStaticClientDexConfig, Secrets: goodSecretswithCRLF, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.NotNil(t, config) var dexCfg map[string]interface{} @@ -325,7 +325,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: "http://localhost", DexConfig: goodDexConfigWithOauthOverrides, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.NotNil(t, config) var dexCfg map[string]interface{} @@ -348,7 +348,7 @@ func Test_GenerateDexConfig(t *testing.T) { URL: "http://localhost", DexConfig: goodDexConfigWithEnabledApprovalScreen, } - config, err := GenerateDexConfigYAML(&s) + config, err := GenerateDexConfigYAML(&s, false) assert.NoError(t, err) assert.NotNil(t, config) var dexCfg map[string]interface{} @@ -377,7 +377,7 @@ func Test_DexReverseProxy(t *testing.T) { })) defer fakeDex.Close() fmt.Printf("Fake Dex listening on %s\n", fakeDex.URL) - server := httptest.NewServer(http.HandlerFunc(NewDexHTTPReverseProxy(fakeDex.URL, "/"))) + server := httptest.NewServer(http.HandlerFunc(NewDexHTTPReverseProxy(fakeDex.URL, "/", nil))) fmt.Printf("Fake API Server listening on %s\n", server.URL) defer server.Close() target, _ := url.Parse(fakeDex.URL) @@ -395,7 +395,7 @@ func Test_DexReverseProxy(t *testing.T) { })) defer fakeDex.Close() fmt.Printf("Fake Dex listening on %s\n", fakeDex.URL) - server := httptest.NewServer(http.HandlerFunc(NewDexHTTPReverseProxy(fakeDex.URL, "/"))) + server := httptest.NewServer(http.HandlerFunc(NewDexHTTPReverseProxy(fakeDex.URL, "/", nil))) fmt.Printf("Fake API Server listening on %s\n", server.URL) defer server.Close() client := &http.Client{ @@ -414,7 +414,7 @@ func Test_DexReverseProxy(t *testing.T) { t.Run("Invalid URL for Dex reverse proxy", func(t *testing.T) { // Can't test for now, since it would call exit t.Skip() - f := NewDexHTTPReverseProxy(invalidURL, "/") + f := NewDexHTTPReverseProxy(invalidURL, "/", nil) assert.Nil(t, f) }) diff --git a/util/oidc/oidc.go b/util/oidc/oidc.go index 030388e0c6365..fd34e7d2b9647 100644 --- a/util/oidc/oidc.go +++ b/util/oidc/oidc.go @@ -81,7 +81,7 @@ func GetScopesOrDefault(scopes []string) []string { // NewClientApp will register the Argo CD client app (either via Dex or external OIDC) and return an // object which has HTTP handlers for handling the HTTP responses for login and callback -func NewClientApp(settings *settings.ArgoCDSettings, dexServerAddr, baseHRef string) (*ClientApp, error) { +func NewClientApp(settings *settings.ArgoCDSettings, dexServerAddr string, dexTlsConfig *dex.DexTLSConfig, baseHRef string) (*ClientApp, error) { redirectURL, err := settings.RedirectURL() if err != nil { return nil, err @@ -103,21 +103,26 @@ func NewClientApp(settings *settings.ArgoCDSettings, dexServerAddr, baseHRef str if err != nil { return nil, fmt.Errorf("parse redirect-uri: %v", err) } - tlsConfig := settings.OIDCTLSConfig() + + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } a.client = &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: tlsConfig, - Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - }, + Transport: transport, } + if settings.DexConfig != "" && settings.OIDCConfigRAW == "" { - a.client.Transport = dex.NewDexRewriteURLRoundTripper(dexServerAddr, a.client.Transport) + transport.TLSClientConfig = dex.TLSConfig(dexTlsConfig) + addrWithProto := dex.DexServerAddressWithProtocol(dexServerAddr, dexTlsConfig) + a.client.Transport = dex.NewDexRewriteURLRoundTripper(addrWithProto, a.client.Transport) + } else { + transport.TLSClientConfig = settings.OIDCTLSConfig() } if os.Getenv(common.EnvVarSSODebug) == "1" { a.client.Transport = httputil.DebugTransport{T: a.client.Transport} diff --git a/util/oidc/oidc_test.go b/util/oidc/oidc_test.go index 4136a1948e616..eec2941384e4b 100644 --- a/util/oidc/oidc_test.go +++ b/util/oidc/oidc_test.go @@ -21,6 +21,7 @@ import ( "github.com/argoproj/argo-cd/v2/server/settings/oidc" "github.com/argoproj/argo-cd/v2/util" "github.com/argoproj/argo-cd/v2/util/crypto" + "github.com/argoproj/argo-cd/v2/util/dex" "github.com/argoproj/argo-cd/v2/util/settings" "github.com/argoproj/argo-cd/v2/util/test" ) @@ -125,7 +126,7 @@ clientID: xxx clientSecret: yyy requestedScopes: ["oidc"]`, oidcTestServer.URL), } - app, err := NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") require.NoError(t, err) req := httptest.NewRequest("GET", "https://argocd.example.com/auth/login", nil) @@ -140,7 +141,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), cdSettings.OIDCTLSInsecureSkipVerify = true - app, err = NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") require.NoError(t, err) w = httptest.NewRecorder() @@ -165,7 +166,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), require.NoError(t, err) cdSettings.Certificate = &cert - app, err := NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") require.NoError(t, err) req := httptest.NewRequest("GET", "https://argocd.example.com/auth/login", nil) @@ -178,9 +179,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), t.Fatal("did not receive expected certificate verification failure error") } - cdSettings.OIDCTLSInsecureSkipVerify = true - - app, err = NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, &dex.DexTLSConfig{StrictValidation: false}, "https://argocd.example.com") require.NoError(t, err) w = httptest.NewRecorder() @@ -209,7 +208,7 @@ clientID: xxx clientSecret: yyy requestedScopes: ["oidc"]`, oidcTestServer.URL), } - app, err := NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") require.NoError(t, err) req := httptest.NewRequest("GET", "https://argocd.example.com/auth/callback", nil) @@ -224,7 +223,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), cdSettings.OIDCTLSInsecureSkipVerify = true - app, err = NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") require.NoError(t, err) w = httptest.NewRecorder() @@ -249,7 +248,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), require.NoError(t, err) cdSettings.Certificate = &cert - app, err := NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") require.NoError(t, err) req := httptest.NewRequest("GET", "https://argocd.example.com/auth/callback", nil) @@ -262,9 +261,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), t.Fatal("did not receive expected certificate verification failure error") } - cdSettings.OIDCTLSInsecureSkipVerify = true - - app, err = NewClientApp(cdSettings, dexTestServer.URL, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, &dex.DexTLSConfig{StrictValidation: false}, "https://argocd.example.com") require.NoError(t, err) w = httptest.NewRecorder() @@ -363,7 +360,7 @@ func TestGenerateAppState(t *testing.T) { signature, err := util.MakeSignature(32) require.NoError(t, err) expectedReturnURL := "http://argocd.example.com/" - app, err := NewClientApp(&settings.ArgoCDSettings{ServerSignature: signature, URL: expectedReturnURL}, "", "") + app, err := NewClientApp(&settings.ArgoCDSettings{ServerSignature: signature, URL: expectedReturnURL}, "", nil, "") require.NoError(t, err) generateResponse := httptest.NewRecorder() state, err := app.generateAppState(expectedReturnURL, generateResponse) @@ -397,10 +394,10 @@ func TestGenerateAppState_XSS(t *testing.T) { app, err := NewClientApp( &settings.ArgoCDSettings{ // Only return URLs starting with this base should be allowed. - URL: "https://argocd.example.com", + URL: "https://argocd.example.com", ServerSignature: signature, }, - "", "", + "", nil, "", ) require.NoError(t, err) @@ -452,7 +449,7 @@ func TestGenerateAppState_NoReturnURL(t *testing.T) { encrypted, err := crypto.Encrypt([]byte("123"), key) require.NoError(t, err) - app, err := NewClientApp(cdSettings, "", "/argo-cd") + app, err := NewClientApp(cdSettings, "", nil, "/argo-cd") require.NoError(t, err) req.AddCookie(&http.Cookie{Name: common.StateCookieName, Value: hex.EncodeToString(encrypted)}) diff --git a/util/session/sessionmanager.go b/util/session/sessionmanager.go index 9c8d3a56974ca..14f4f489278f3 100644 --- a/util/session/sessionmanager.go +++ b/util/session/sessionmanager.go @@ -111,7 +111,7 @@ func getLoginFailureWindow() time.Duration { } // NewSessionManager creates a new session manager from Argo CD settings -func NewSessionManager(settingsMgr *settings.SettingsManager, projectsLister v1alpha1.AppProjectNamespaceLister, dexServerAddr string, storage UserStateStorage) *SessionManager { +func NewSessionManager(settingsMgr *settings.SettingsManager, projectsLister v1alpha1.AppProjectNamespaceLister, dexServerAddr string, dexTlsConfig *dex.DexTLSConfig, storage UserStateStorage) *SessionManager { s := SessionManager{ settingsMgr: settingsMgr, storage: storage, @@ -123,21 +123,27 @@ func NewSessionManager(settingsMgr *settings.SettingsManager, projectsLister v1a if err != nil { panic(err) } - tlsConfig := settings.OIDCTLSConfig() + + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } + s.client = &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: tlsConfig, - Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - }, + Transport: transport, } + if settings.DexConfig != "" { - s.client.Transport = dex.NewDexRewriteURLRoundTripper(dexServerAddr, s.client.Transport) + transport.TLSClientConfig = dex.TLSConfig(dexTlsConfig) + addrWithProto := dex.DexServerAddressWithProtocol(dexServerAddr, dexTlsConfig) + s.client.Transport = dex.NewDexRewriteURLRoundTripper(addrWithProto, s.client.Transport) + } else { + transport.TLSClientConfig = settings.OIDCTLSConfig() } if os.Getenv(common.EnvVarSSODebug) == "1" { s.client.Transport = httputil.DebugTransport{T: s.client.Transport} diff --git a/util/session/sessionmanager_test.go b/util/session/sessionmanager_test.go index 83327e594ce9c..e646e5016fb0f 100644 --- a/util/session/sessionmanager_test.go +++ b/util/session/sessionmanager_test.go @@ -74,7 +74,7 @@ func getKubeClient(pass string, enabled bool, capabilities ...settings.AccountCa } func newSessionManager(settingsMgr *settings.SettingsManager, projectLister v1alpha1.AppProjectNamespaceLister, storage UserStateStorage) *SessionManager { - mgr := NewSessionManager(settingsMgr, projectLister, "", storage) + mgr := NewSessionManager(settingsMgr, projectLister, "", nil, storage) mgr.verificationDelayNoiseEnabled = false return mgr } @@ -504,7 +504,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), } settingsMgr := settings.NewSettingsManager(context.Background(), getKubeClientWithConfig(dexConfig, nil), "argocd") - mgr := NewSessionManager(settingsMgr, getProjLister(), "", NewUserStateStorage(nil)) + mgr := NewSessionManager(settingsMgr, getProjLister(), "", nil, NewUserStateStorage(nil)) mgr.verificationDelayNoiseEnabled = false // Use test server's client to avoid TLS issues. mgr.client = oidcTestServer.Client() @@ -538,7 +538,7 @@ rootCA: | } settingsMgr := settings.NewSettingsManager(context.Background(), getKubeClientWithConfig(dexConfig, nil), "argocd") - mgr := NewSessionManager(settingsMgr, getProjLister(), "", NewUserStateStorage(nil)) + mgr := NewSessionManager(settingsMgr, getProjLister(), "", nil, NewUserStateStorage(nil)) mgr.verificationDelayNoiseEnabled = false claims := jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))} @@ -575,7 +575,7 @@ rootCA: | } settingsMgr := settings.NewSettingsManager(context.Background(), getKubeClientWithConfig(dexConfig, secretConfig), "argocd") - mgr := NewSessionManager(settingsMgr, getProjLister(), dexTestServer.URL, NewUserStateStorage(nil)) + mgr := NewSessionManager(settingsMgr, getProjLister(), dexTestServer.URL, nil, NewUserStateStorage(nil)) mgr.verificationDelayNoiseEnabled = false claims := jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))} @@ -612,7 +612,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), } settingsMgr := settings.NewSettingsManager(context.Background(), getKubeClientWithConfig(dexConfig, secretConfig), "argocd") - mgr := NewSessionManager(settingsMgr, getProjLister(), "", NewUserStateStorage(nil)) + mgr := NewSessionManager(settingsMgr, getProjLister(), "", nil, NewUserStateStorage(nil)) mgr.verificationDelayNoiseEnabled = false claims := jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))} @@ -649,7 +649,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), } settingsMgr := settings.NewSettingsManager(context.Background(), getKubeClientWithConfig(dexConfig, secretConfig), "argocd") - mgr := NewSessionManager(settingsMgr, getProjLister(), dexTestServer.URL, NewUserStateStorage(nil)) + mgr := NewSessionManager(settingsMgr, getProjLister(), dexTestServer.URL, nil, NewUserStateStorage(nil)) mgr.verificationDelayNoiseEnabled = false claims := jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))} @@ -687,7 +687,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), } settingsMgr := settings.NewSettingsManager(context.Background(), getKubeClientWithConfig(dexConfig, secretConfig), "argocd") - mgr := NewSessionManager(settingsMgr, getProjLister(), "", NewUserStateStorage(nil)) + mgr := NewSessionManager(settingsMgr, getProjLister(), "", nil, NewUserStateStorage(nil)) mgr.verificationDelayNoiseEnabled = false claims := jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))} @@ -716,7 +716,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), } settingsMgr := settings.NewSettingsManager(context.Background(), getKubeClientWithConfig(dexConfig, nil), "argocd") - mgr := NewSessionManager(settingsMgr, getProjLister(), "", NewUserStateStorage(nil)) + mgr := NewSessionManager(settingsMgr, getProjLister(), "", nil, NewUserStateStorage(nil)) mgr.verificationDelayNoiseEnabled = false claims := jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))} diff --git a/util/tls/tls.go b/util/tls/tls.go index 9712ecbd7b390..d963eed55cee7 100644 --- a/util/tls/tls.go +++ b/util/tls/tls.go @@ -362,6 +362,23 @@ func LoadX509CertPool(paths ...string) (*x509.CertPool, error) { return pool, nil } +// LoadX509Cert loads PEM data from a file and returns the resulting Certificate +func LoadX509Cert(path string) (*x509.Certificate, error) { + bytes, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("could not read certificate file: %v", err) + } + block, _ := pem.Decode(bytes) + if block == nil { + return nil, fmt.Errorf("could not decode PEM") + } + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, fmt.Errorf("could not parse certificate: %v", err) + } + return cert, nil +} + // CreateServerTLSConfig will provide a TLS configuration for a server. It will // either use a certificate and key provided at tlsCertPath and tlsKeyPath, or // if these are not given, will generate a self-signed certificate valid for @@ -396,7 +413,7 @@ func CreateServerTLSConfig(tlsCertPath, tlsKeyPath string, hosts []string) (*tls } if !tlsCertExists || !tlsKeyExists { - log.Infof("Generating self-signed gRPC TLS certificate for this session") + log.Infof("Generating self-signed TLS certificate for this session") c, err := GenerateX509KeyPair(CertOptions{ Hosts: hosts, Organization: "Argo CD", @@ -407,10 +424,10 @@ func CreateServerTLSConfig(tlsCertPath, tlsKeyPath string, hosts []string) (*tls } cert = c } else { - log.Infof("Loading gRPC TLS configuration from cert=%s and key=%s", tlsCertPath, tlsKeyPath) + log.Infof("Loading TLS configuration from cert=%s and key=%s", tlsCertPath, tlsKeyPath) c, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath) if err != nil { - return nil, fmt.Errorf("Unable to initalize gRPC TLS configuration with cert=%s and key=%s: %v", tlsCertPath, tlsKeyPath, err) + return nil, fmt.Errorf("Unable to initalize TLS configuration with cert=%s and key=%s: %v", tlsCertPath, tlsKeyPath, err) } cert = &c }