Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add HTTPS to dex server (#9424) #9883

Merged
29 changes: 26 additions & 3 deletions cmd/argocd-dex/commands/argocd_dex.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -44,6 +46,7 @@ func NewCommand() *cobra.Command {
func NewRunDexCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
disableTLS bool
)
var command = cobra.Command{
Use: "rundex",
Expand All @@ -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)
Expand All @@ -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")
Expand All @@ -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
Expand All @@ -119,13 +138,15 @@ 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
}

func NewGenDexConfigCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
out string
disableTLS bool
)
var command = cobra.Command{
Use: "gendexcfg",
Expand All @@ -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()
Expand All @@ -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")
Expand Down Expand Up @@ -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
}

Expand Down
28 changes: 28 additions & 0 deletions cmd/argocd-server/commands/argocd_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -66,6 +67,8 @@ func NewCommand() *cobra.Command {
contentSecurityPolicy string
repoServerPlaintext bool
repoServerStrictTLS bool
dexServerPlaintext bool
dexServerStrictTLS bool
staticAssetsDir string
)
var command = &cobra.Command{
Expand Down Expand Up @@ -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 {
Expand All @@ -148,6 +173,7 @@ func NewCommand() *cobra.Command {
AppClientset: appClientSet,
RepoClientset: repoclientset,
DexServerAddr: dexServerAddress,
DexTLSConfig: dexTlsConfig,
DisableAuth: disableAuth,
EnableGZip: enableGZip,
TLSConfigCustomizer: tlsConfigCustomizer,
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down
7 changes: 7 additions & 0 deletions docs/operator-manual/argocd-cmd-params-cm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
crenshaw-dev marked this conversation as resolved.
Show resolved Hide resolved
# Disable client authentication
server.disable.auth: "false"
# Enable GZIP compression
Expand Down Expand Up @@ -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"
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion docs/operator-manual/server-commands/argocd-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
98 changes: 96 additions & 2 deletions docs/operator-manual/tls.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 <address>`
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.

7 changes: 7 additions & 0 deletions docs/operator-manual/upgrading/2.4-2.5.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Loading