mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 01:28:45 +01:00
feat: Make TLS to repo-server configurable and optional (#5764)
feat: Make TLS to repo-server configurable and optional (#5764) Signed-off-by: jannfis <jann@mistrust.net>
This commit is contained in:
@@ -2,6 +2,7 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/errors"
|
||||
kubeutil "github.com/argoproj/argo-cd/util/kube"
|
||||
"github.com/argoproj/argo-cd/util/settings"
|
||||
"github.com/argoproj/argo-cd/util/tls"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,6 +52,8 @@ func NewCommand() *cobra.Command {
|
||||
kubectlParallelismLimit int64
|
||||
cacheSrc func() (*appstatecache.Cache, error)
|
||||
redisClient *redis.Client
|
||||
repoServerPlaintext bool
|
||||
repoServerStrictTLS bool
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -72,7 +76,26 @@ func NewCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
|
||||
resyncDuration := time.Duration(appResyncPeriod) * time.Second
|
||||
repoClientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds)
|
||||
tlsConfig := apiclient.TLSConfiguration{
|
||||
DisableTLS: repoServerPlaintext,
|
||||
StrictValidation: repoServerStrictTLS,
|
||||
}
|
||||
|
||||
// Load CA information to use for validating connections to the
|
||||
// repository server, if strict TLS validation was requested.
|
||||
if !repoServerPlaintext && repoServerStrictTLS {
|
||||
pool, err := tls.LoadX509CertPool(
|
||||
fmt.Sprintf("%s/controller/tls/tls.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)),
|
||||
fmt.Sprintf("%s/controller/tls/ca.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
tlsConfig.Certificates = pool
|
||||
}
|
||||
|
||||
repoClientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds, tlsConfig)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
@@ -126,6 +149,8 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().DurationVar(&metricsCacheExpiration, "metrics-cache-expiration", 0*time.Second, "Prometheus metrics cache expiration (disabled by default. e.g. 24h0m0s)")
|
||||
command.Flags().IntVar(&selfHealTimeoutSeconds, "self-heal-timeout-seconds", 5, "Specifies timeout between application self heal attempts")
|
||||
command.Flags().Int64Var(&kubectlParallelismLimit, "kubectl-parallelism-limit", 20, "Number of allowed concurrent kubectl fork/execs. Any value less the 1 means no limit.")
|
||||
command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", false, "Disable TLS on connections to repo server")
|
||||
command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", false, "Whether to use strict validation of the TLS cert presented by the repo server")
|
||||
cacheSrc = appstatecache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
|
||||
redisClient = client
|
||||
})
|
||||
|
||||
@@ -67,8 +67,10 @@ func NewCommand() *cobra.Command {
|
||||
listenPort int
|
||||
metricsPort int
|
||||
cacheSrc func() (*reposervercache.Cache, error)
|
||||
tlsConfigCustomizer tls.ConfigCustomizer
|
||||
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
|
||||
redisClient *redis.Client
|
||||
disableTLS bool
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -79,8 +81,11 @@ func NewCommand() *cobra.Command {
|
||||
cli.SetLogFormat(cmdutil.LogFormat)
|
||||
cli.SetLogLevel(cmdutil.LogLevel)
|
||||
|
||||
tlsConfigCustomizer, err := tlsConfigCustomizerSrc()
|
||||
errors.CheckError(err)
|
||||
if !disableTLS {
|
||||
var err error
|
||||
tlsConfigCustomizer, err = tlsConfigCustomizerSrc()
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
cache, err := cacheSrc()
|
||||
errors.CheckError(err)
|
||||
@@ -104,7 +109,7 @@ func NewCommand() *cobra.Command {
|
||||
// connect to itself to make sure repo server is able to serve connection
|
||||
// used by liveness probe to auto restart repo server
|
||||
// see https://github.com/argoproj/argo-cd/issues/5110 for more information
|
||||
conn, err := apiclient.NewConnection(fmt.Sprintf("localhost:%d", listenPort), 60)
|
||||
conn, err := apiclient.NewConnection(fmt.Sprintf("localhost:%d", listenPort), 60, &apiclient.TLSConfiguration{DisableTLS: disableTLS})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -152,6 +157,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().Int64Var(¶llelismLimit, "parallelismlimit", 0, "Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit.")
|
||||
command.Flags().IntVar(&listenPort, "port", common.DefaultPortRepoServer, "Listen on given port for incoming connections")
|
||||
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortRepoServerMetrics, "Start metrics server on given port")
|
||||
command.Flags().BoolVar(&disableTLS, "disable-tls", false, "Disable TLS on the gRPC endpoint")
|
||||
|
||||
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
|
||||
cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/pkg/stats"
|
||||
@@ -60,6 +61,8 @@ func NewCommand() *cobra.Command {
|
||||
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
|
||||
cacheSrc func() (*servercache.Cache, error)
|
||||
frameOptions string
|
||||
repoServerPlaintext bool
|
||||
repoServerStrictTLS bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -93,8 +96,25 @@ func NewCommand() *cobra.Command {
|
||||
appclientsetConfig = kube.AddFailureRetryWrapper(appclientsetConfig, failureRetryCount, failureRetryPeriodMilliSeconds)
|
||||
}
|
||||
appclientset := appclientset.NewForConfigOrDie(appclientsetConfig)
|
||||
repoclientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds)
|
||||
tlsConfig := apiclient.TLSConfiguration{
|
||||
DisableTLS: repoServerPlaintext,
|
||||
StrictValidation: repoServerStrictTLS,
|
||||
}
|
||||
|
||||
// Load CA information to use for validating connections to the
|
||||
// repository server, if strict TLS validation was requested.
|
||||
if !repoServerPlaintext && repoServerStrictTLS {
|
||||
pool, err := tls.LoadX509CertPool(
|
||||
fmt.Sprintf("%s/server/tls/tls.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)),
|
||||
fmt.Sprintf("%s/server/tls/ca.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
tlsConfig.Certificates = pool
|
||||
}
|
||||
|
||||
repoclientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds, tlsConfig)
|
||||
if rootPath != "" {
|
||||
if baseHRef != "" && baseHRef != rootPath {
|
||||
log.Warnf("--basehref and --rootpath had conflict: basehref: %s rootpath: %s", baseHRef, rootPath)
|
||||
@@ -153,6 +173,8 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortArgoCDAPIServerMetrics, "Start metrics on given port")
|
||||
command.Flags().IntVar(&repoServerTimeoutSeconds, "repo-server-timeout-seconds", 60, "Repo server RPC call timeout seconds.")
|
||||
command.Flags().StringVar(&frameOptions, "x-frame-options", "sameorigin", "Set X-Frame-Options header in HTTP responses to `value`. To disable, set to \"\".")
|
||||
command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", false, "Use a plaintext client (non-TLS) to connect to repository server")
|
||||
command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", false, "Perform strict validation of TLS certificates when connecting to repo server")
|
||||
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command)
|
||||
cacheSrc = servercache.AddCacheFlagsToCmd(command, func(client *redis.Client) {
|
||||
redisClient = client
|
||||
|
||||
@@ -251,7 +251,7 @@ func NewReconcileCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
repoServerAddress = fmt.Sprintf("localhost:%d", repoServerPort)
|
||||
}
|
||||
repoServerClient := apiclient.NewRepoServerClientset(repoServerAddress, 60)
|
||||
repoServerClient := apiclient.NewRepoServerClientset(repoServerAddress, 60, apiclient.TLSConfiguration{DisableTLS: false, StrictValidation: false})
|
||||
|
||||
appClientset := appclientset.NewForConfigOrDie(cfg)
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(cfg)
|
||||
|
||||
@@ -53,6 +53,8 @@ const (
|
||||
DefaultSSHKnownHostsName = "ssh_known_hosts"
|
||||
// Default path to GnuPG home directory
|
||||
DefaultGnuPgHomePath = "/app/config/gpg/keys"
|
||||
// Default path to repo server TLS endpoint config
|
||||
DefaultAppConfigPath = "/app/config"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -196,6 +198,8 @@ const (
|
||||
EnvGithubAppCredsExpirationDuration = "ARGOCD_GITHUB_APP_CREDS_EXPIRATION_DURATION"
|
||||
// EnvHelmIndexCacheDuration controls how the helm repository index file is cached for (default: 0)
|
||||
EnvHelmIndexCacheDuration = "ARGOCD_HELM_INDEX_CACHE_DURATION"
|
||||
// EnvRepoServerConfigPath allows to override the configuration path for repo server
|
||||
EnvAppConfigPath = "ARGOCD_APP_CONF_PATH"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -38,6 +38,8 @@ argocd-application-controller [flags]
|
||||
--redis string Redis server hostname and port (e.g. argocd-redis:6379).
|
||||
--redisdb int Redis database.
|
||||
--repo-server string Repo server address. (default "argocd-repo-server:8081")
|
||||
--repo-server-plaintext Disable TLS on connections to repo server
|
||||
--repo-server-strict-tls Whether to use strict validation of the TLS cert presented by the repo server
|
||||
--repo-server-timeout-seconds int Repo server RPC call timeout seconds. (default 60)
|
||||
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
|
||||
--self-heal-timeout-seconds int Specifies timeout between application self heal attempts (default 5)
|
||||
|
||||
@@ -14,6 +14,7 @@ argocd-repo-server [flags]
|
||||
|
||||
```
|
||||
--default-cache-expiration duration Cache expiration default (default 24h0m0s)
|
||||
--disable-tls Disable TLS on the gRPC endpoint
|
||||
-h, --help help for argocd-repo-server
|
||||
--logformat string Set the logging format. One of: text|json (default "text")
|
||||
--loglevel string Set the logging level. One of: debug|info|warn|error (default "info")
|
||||
|
||||
@@ -43,6 +43,8 @@ argocd-server [flags]
|
||||
--redis string Redis server hostname and port (e.g. argocd-redis:6379).
|
||||
--redisdb int Redis database.
|
||||
--repo-server string Repo server address (default "argocd-repo-server:8081")
|
||||
--repo-server-plaintext Use a plaintext client (non-TLS) to connect to repository server
|
||||
--repo-server-strict-tls Perform strict validation of TLS certificates when connecting to repo server
|
||||
--repo-server-timeout-seconds int Repo server RPC call timeout seconds. (default 60)
|
||||
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
|
||||
--rootpath string Used if Argo CD is running behind reverse proxy under subpath different from /
|
||||
|
||||
@@ -41,6 +41,9 @@ spec:
|
||||
port: 8082
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumeMounts:
|
||||
- name: argocd-repo-server-tls
|
||||
mountPath: /app/config/controller/tls
|
||||
serviceAccountName: argocd-application-controller
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
@@ -57,3 +60,15 @@ spec:
|
||||
matchLabels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
topologyKey: kubernetes.io/hostname
|
||||
volumes:
|
||||
- name: argocd-repo-server-tls
|
||||
secret:
|
||||
secretName: argocd-repo-server-tls
|
||||
optional: true
|
||||
items:
|
||||
- key: tls.crt
|
||||
path: tls.crt
|
||||
- key: tls.key
|
||||
path: tls.key
|
||||
- key: ca.crt
|
||||
path: ca.crt
|
||||
@@ -50,6 +50,8 @@ spec:
|
||||
mountPath: /app/config/gpg/source
|
||||
- name: gpg-keyring
|
||||
mountPath: /app/config/gpg/keys
|
||||
- name: argocd-repo-server-tls
|
||||
mountPath: /app/config/reposerver/tls
|
||||
volumes:
|
||||
- name: ssh-known-hosts
|
||||
configMap:
|
||||
@@ -62,6 +64,17 @@ spec:
|
||||
name: argocd-gpg-keys-cm
|
||||
- name: gpg-keyring
|
||||
emptyDir: {}
|
||||
- name: argocd-repo-server-tls
|
||||
secret:
|
||||
secretName: argocd-repo-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:
|
||||
|
||||
@@ -26,6 +26,8 @@ spec:
|
||||
mountPath: /app/config/ssh
|
||||
- name: tls-certs
|
||||
mountPath: /app/config/tls
|
||||
- name: argocd-repo-server-tls
|
||||
mountPath: /app/config/server/tls
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
- containerPort: 8083
|
||||
@@ -50,6 +52,17 @@ spec:
|
||||
- name: tls-certs
|
||||
configMap:
|
||||
name: argocd-tls-certs-cm
|
||||
- name: argocd-repo-server-tls
|
||||
secret:
|
||||
secretName: argocd-repo-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:
|
||||
|
||||
@@ -3338,6 +3338,8 @@ spec:
|
||||
name: gpg-keys
|
||||
- mountPath: /app/config/gpg/keys
|
||||
name: gpg-keyring
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
volumes:
|
||||
- configMap:
|
||||
name: argocd-ssh-known-hosts-cm
|
||||
@@ -3350,6 +3352,17 @@ spec:
|
||||
name: gpg-keys
|
||||
- emptyDir: {}
|
||||
name: gpg-keyring
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -3416,6 +3429,8 @@ spec:
|
||||
name: ssh-known-hosts
|
||||
- mountPath: /app/config/tls
|
||||
name: tls-certs
|
||||
- mountPath: /app/config/server/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
@@ -3426,6 +3441,17 @@ spec:
|
||||
- configMap:
|
||||
name: argocd-tls-certs-cm
|
||||
name: tls-certs
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
@@ -3487,7 +3513,22 @@ spec:
|
||||
port: 8082
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/controller/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-application-controller
|
||||
volumes:
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
|
||||
@@ -3253,6 +3253,8 @@ spec:
|
||||
name: gpg-keys
|
||||
- mountPath: /app/config/gpg/keys
|
||||
name: gpg-keyring
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
volumes:
|
||||
- configMap:
|
||||
name: argocd-ssh-known-hosts-cm
|
||||
@@ -3265,6 +3267,17 @@ spec:
|
||||
name: gpg-keys
|
||||
- emptyDir: {}
|
||||
name: gpg-keyring
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -3331,6 +3344,8 @@ spec:
|
||||
name: ssh-known-hosts
|
||||
- mountPath: /app/config/tls
|
||||
name: tls-certs
|
||||
- mountPath: /app/config/server/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
@@ -3341,6 +3356,17 @@ spec:
|
||||
- configMap:
|
||||
name: argocd-tls-certs-cm
|
||||
name: tls-certs
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
@@ -3402,7 +3428,22 @@ spec:
|
||||
port: 8082
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/controller/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-application-controller
|
||||
volumes:
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
|
||||
@@ -2672,6 +2672,8 @@ spec:
|
||||
name: gpg-keys
|
||||
- mountPath: /app/config/gpg/keys
|
||||
name: gpg-keyring
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
volumes:
|
||||
- configMap:
|
||||
name: argocd-ssh-known-hosts-cm
|
||||
@@ -2684,6 +2686,17 @@ spec:
|
||||
name: gpg-keys
|
||||
- emptyDir: {}
|
||||
name: gpg-keyring
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -2745,6 +2758,8 @@ spec:
|
||||
name: ssh-known-hosts
|
||||
- mountPath: /app/config/tls
|
||||
name: tls-certs
|
||||
- mountPath: /app/config/server/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
@@ -2755,6 +2770,17 @@ spec:
|
||||
- configMap:
|
||||
name: argocd-tls-certs-cm
|
||||
name: tls-certs
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
@@ -2814,4 +2840,19 @@ spec:
|
||||
port: 8082
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/controller/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-application-controller
|
||||
volumes:
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
|
||||
@@ -2587,6 +2587,8 @@ spec:
|
||||
name: gpg-keys
|
||||
- mountPath: /app/config/gpg/keys
|
||||
name: gpg-keyring
|
||||
- mountPath: /app/config/reposerver/tls
|
||||
name: argocd-repo-server-tls
|
||||
volumes:
|
||||
- configMap:
|
||||
name: argocd-ssh-known-hosts-cm
|
||||
@@ -2599,6 +2601,17 @@ spec:
|
||||
name: gpg-keys
|
||||
- emptyDir: {}
|
||||
name: gpg-keyring
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -2660,6 +2673,8 @@ spec:
|
||||
name: ssh-known-hosts
|
||||
- mountPath: /app/config/tls
|
||||
name: tls-certs
|
||||
- mountPath: /app/config/server/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
@@ -2670,6 +2685,17 @@ spec:
|
||||
- configMap:
|
||||
name: argocd-tls-certs-cm
|
||||
name: tls-certs
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
@@ -2729,4 +2755,19 @@ spec:
|
||||
port: 8082
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumeMounts:
|
||||
- mountPath: /app/config/controller/tls
|
||||
name: argocd-repo-server-tls
|
||||
serviceAccountName: argocd-application-controller
|
||||
volumes:
|
||||
- name: argocd-repo-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-repo-server-tls
|
||||
|
||||
@@ -2,6 +2,7 @@ package apiclient
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"time"
|
||||
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
@@ -19,6 +20,16 @@ const (
|
||||
MaxGRPCMessageSize = 100 * 1024 * 1024
|
||||
)
|
||||
|
||||
// TLSConfiguration describes parameters for TLS configuration to be used by a repo server API client
|
||||
type TLSConfiguration struct {
|
||||
// Whether to disable TLS for connections
|
||||
DisableTLS bool
|
||||
// Whether to enforce strict validation of TLS certificates
|
||||
StrictValidation bool
|
||||
// List of certificates to validate the peer against (if StrictCerts is true)
|
||||
Certificates *x509.CertPool
|
||||
}
|
||||
|
||||
// Clientset represents repository server api clients
|
||||
type Clientset interface {
|
||||
NewRepoServerClient() (io.Closer, RepoServerServiceClient, error)
|
||||
@@ -27,17 +38,18 @@ type Clientset interface {
|
||||
type clientSet struct {
|
||||
address string
|
||||
timeoutSeconds int
|
||||
tlsConfig TLSConfiguration
|
||||
}
|
||||
|
||||
func (c *clientSet) NewRepoServerClient() (io.Closer, RepoServerServiceClient, error) {
|
||||
conn, err := NewConnection(c.address, c.timeoutSeconds)
|
||||
conn, err := NewConnection(c.address, c.timeoutSeconds, &c.tlsConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return conn, NewRepoServerServiceClient(conn), nil
|
||||
}
|
||||
|
||||
func NewConnection(address string, timeoutSeconds int) (*grpc.ClientConn, error) {
|
||||
func NewConnection(address string, timeoutSeconds int, tlsConfig *TLSConfiguration) (*grpc.ClientConn, error) {
|
||||
retryOpts := []grpc_retry.CallOption{
|
||||
grpc_retry.WithMax(3),
|
||||
grpc_retry.WithBackoff(grpc_retry.BackoffLinear(1000 * time.Millisecond)),
|
||||
@@ -47,12 +59,23 @@ func NewConnection(address string, timeoutSeconds int) (*grpc.ClientConn, error)
|
||||
unaryInterceptors = append(unaryInterceptors, argogrpc.WithTimeout(time.Duration(timeoutSeconds)*time.Second))
|
||||
}
|
||||
opts := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})),
|
||||
grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(retryOpts...)),
|
||||
grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(unaryInterceptors...)),
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize), grpc.MaxCallSendMsgSize(MaxGRPCMessageSize)),
|
||||
}
|
||||
|
||||
tlsC := &tls.Config{}
|
||||
if !tlsConfig.DisableTLS {
|
||||
if !tlsConfig.StrictValidation {
|
||||
tlsC.InsecureSkipVerify = true
|
||||
} else {
|
||||
tlsC.RootCAs = tlsConfig.Certificates
|
||||
}
|
||||
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsC)))
|
||||
} else {
|
||||
opts = append(opts, grpc.WithInsecure())
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(address, opts...)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to connect to repository service with address %s", address)
|
||||
@@ -62,6 +85,6 @@ func NewConnection(address string, timeoutSeconds int) (*grpc.ClientConn, error)
|
||||
}
|
||||
|
||||
// NewRepoServerClientset creates new instance of repo server Clientset
|
||||
func NewRepoServerClientset(address string, timeoutSeconds int) Clientset {
|
||||
return &clientSet{address: address, timeoutSeconds: timeoutSeconds}
|
||||
func NewRepoServerClientset(address string, timeoutSeconds int, tlsConfig TLSConfiguration) Clientset {
|
||||
return &clientSet{address: address, timeoutSeconds: timeoutSeconds, tlsConfig: tlsConfig}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package reposerver
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/reposerver/metrics"
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
"github.com/argoproj/argo-cd/server/version"
|
||||
"github.com/argoproj/argo-cd/util/env"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
tlsutil "github.com/argoproj/argo-cd/util/tls"
|
||||
)
|
||||
@@ -34,24 +36,25 @@ type ArgoCDRepoServer struct {
|
||||
initConstants repository.RepoServerInitConstants
|
||||
}
|
||||
|
||||
// The hostnames to generate self-signed issues with
|
||||
var tlsHostList []string = []string{"localhost", "reposerver"}
|
||||
|
||||
// NewServer returns a new instance of the Argo CD Repo server
|
||||
func NewServer(metricsServer *metrics.MetricsServer, cache *reposervercache.Cache, tlsConfCustomizer tlsutil.ConfigCustomizer, initConstants repository.RepoServerInitConstants) (*ArgoCDRepoServer, error) {
|
||||
// generate TLS cert
|
||||
hosts := []string{
|
||||
"localhost",
|
||||
"argocd-repo-server",
|
||||
}
|
||||
cert, err := tlsutil.GenerateX509KeyPair(tlsutil.CertOptions{
|
||||
Hosts: hosts,
|
||||
Organization: "Argo CD",
|
||||
IsCA: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tlsConfig *tls.Config
|
||||
|
||||
tlsConfig := &tls.Config{Certificates: []tls.Certificate{*cert}}
|
||||
tlsConfCustomizer(tlsConfig)
|
||||
// Generate or load TLS server certificates to use with this instance of
|
||||
// repository server.
|
||||
if tlsConfCustomizer != nil {
|
||||
var err error
|
||||
certPath := fmt.Sprintf("%s/reposerver/tls/tls.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath))
|
||||
keyPath := fmt.Sprintf("%s/reposerver/tls/tls.key", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath))
|
||||
tlsConfig, err = tlsutil.CreateServerTLSConfig(certPath, keyPath, tlsHostList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfCustomizer(tlsConfig)
|
||||
}
|
||||
|
||||
if os.Getenv(common.EnvEnableGRPCTimeHistogramEnv) == "true" {
|
||||
grpc_prometheus.EnableHandlingTimeHistogram()
|
||||
@@ -61,18 +64,25 @@ func NewServer(metricsServer *metrics.MetricsServer, cache *reposervercache.Cach
|
||||
streamInterceptors := []grpc.StreamServerInterceptor{grpc_logrus.StreamServerInterceptor(serverLog), grpc_prometheus.StreamServerInterceptor, grpc_util.PanicLoggerStreamServerInterceptor(serverLog)}
|
||||
unaryInterceptors := []grpc.UnaryServerInterceptor{grpc_logrus.UnaryServerInterceptor(serverLog), grpc_prometheus.UnaryServerInterceptor, grpc_util.PanicLoggerUnaryServerInterceptor(serverLog)}
|
||||
|
||||
serverOpts := []grpc.ServerOption{
|
||||
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptors...)),
|
||||
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(streamInterceptors...)),
|
||||
grpc.MaxRecvMsgSize(apiclient.MaxGRPCMessageSize),
|
||||
grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize),
|
||||
}
|
||||
|
||||
// We do allow for non-TLS servers to be created, in case of mTLS will be
|
||||
// implemented by e.g. a sidecar container.
|
||||
if tlsConfig != nil {
|
||||
serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(tlsConfig)))
|
||||
}
|
||||
|
||||
return &ArgoCDRepoServer{
|
||||
log: serverLog,
|
||||
metricsServer: metricsServer,
|
||||
cache: cache,
|
||||
initConstants: initConstants,
|
||||
opts: []grpc.ServerOption{
|
||||
grpc.Creds(credentials.NewTLS(tlsConfig)),
|
||||
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptors...)),
|
||||
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(streamInterceptors...)),
|
||||
grpc.MaxRecvMsgSize(apiclient.MaxGRPCMessageSize),
|
||||
grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize),
|
||||
},
|
||||
opts: serverOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
8
util/env/env.go
vendored
8
util/env/env.go
vendored
@@ -61,3 +61,11 @@ func ParseDurationFromEnv(env string, defaultValue, min, max time.Duration) time
|
||||
}
|
||||
return dur
|
||||
}
|
||||
|
||||
func StringFromEnv(env string, defaultValue string) string {
|
||||
str := os.Getenv(env)
|
||||
if str == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
0
util/tls/testdata/empty_tls.crt
vendored
Normal file
0
util/tls/testdata/empty_tls.crt
vendored
Normal file
0
util/tls/testdata/empty_tls.key
vendored
Normal file
0
util/tls/testdata/empty_tls.key
vendored
Normal file
29
util/tls/testdata/valid_tls.crt
vendored
Normal file
29
util/tls/testdata/valid_tls.crt
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFAzCCAuugAwIBAgIUKPX+VoX8ak9DFlhr0RorfvPbk30wDQYJKoZIhvcNAQEL
|
||||
BQAwETEPMA0GA1UEAwwGU29tZUNOMB4XDTIxMDMxNTA4NTIyN1oXDTIyMDMxNTA4
|
||||
NTIyN1owETEPMA0GA1UEAwwGU29tZUNOMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
|
||||
MIICCgKCAgEA5KAr7vEPbksus5Vf4SeRUx/ZSvqSQ3oILKjYR6TB8Sp/CG1jYoLo
|
||||
leIAme/o9soPpQ9x/fhzLZUvEB35YFrcEzLyHA2Nl4GlaxOJtgwX94D/+alvssHA
|
||||
2z3u6bE9jLNxpBOzzM0iDuAUzqYfahkCdbGuYqMAorWto/WuebbjZanu3RbQrWA6
|
||||
WVQ0cPhAS2dDt/IKrYNpC7AQkvbNm69jntK8wlhM4BsS2kJS3ZD4IkLzF/Ro+f3D
|
||||
AxRmkZyDD+ZMBhRXmbucF8ryxmWmXZwx3D9j0tBTsyj2SEiCqLJkTU/jhBgbdV8e
|
||||
AI1vrkM5d5hQaoGrVXPDcYgJXKiCH6o+6nKO3626M1rLIA239ghnrBr87eboPQSt
|
||||
aKOPNsgQ2BZaJlkOV4pov5ZAUO3hDeXmvMIXAc6sQnxMWcAw/0sTzy57l6pxhur5
|
||||
zyfyfFTkjON5SNMLjj5ELuKsNIecX9Qp1m9IZ+YRnuAAx4eQP6kGgGREXzhNAQbk
|
||||
apyoIqsTHjMVMD4s6nD9eWvmQVL/dm9UqNAxXapxlLc7uqq2uaZV7IZlPOGt40kI
|
||||
LmJBOCjjgiQjBiNckYbpuHox4uRlo1dgjx7P5mSmf71YoiFqIKj3Q8nKvCQ9/y8A
|
||||
pPV/TcCz9iUmAxp8cHbjkD/ed6gLfoNKyVef1U6Z/hHyCtQsMIrQmN0CAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFBv58Vn4WBGvqvlZ/H4DZ9ofXzGpMB8GA1UdIwQYMBaAFBv5
|
||||
8Vn4WBGvqvlZ/H4DZ9ofXzGpMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
|
||||
BQADggIBACRHQhhUH5HEKWKpoSZUYa6Ph3v5g9/tEp8o4zYcfllBmAGSfBatVyOh
|
||||
rKuCphNjyXOZ6oFRl8xFBi3rWEu3nZlYJHmb5wWd9Fe0P4xHGLGKayNl5JKKZ4dq
|
||||
Ypkg4kVvvL+4RexOM6QGDKbwR/wApRAN1/uK2Dv/nuctgJP8tnHX4vGL68ljZyVS
|
||||
tHcQFoVgmCgKvMlvw+Vs+Bj2lzQooPSjkHLKtA242uaUsj0eW4zUn8NWyQIzx/He
|
||||
AAzJXmUtS/dmGbPCkrzNpYQT96QtbcLoeRbKjJViFIzti8EYF6k9mctLRoC+6LVn
|
||||
aeKx2k+6tN9/NS9Pz+hzGyqaJa7jk9QBnhDfrIjXWplTJG5sBakDlpvy+56SUwvq
|
||||
KEfFlDzcAgr09/4X8bBX1x+ty8DbpojQXrHKS/HjavodbPazJxfkshtG6NidcKjB
|
||||
11cVHfAezwurMt3X3AD51JLXbIu9BTy+3KXHsAqv7lfqAa9CrEL5uQ3SL5ZFS8zs
|
||||
+nmFRVzh6GYB+FNKfV6mH/QOXn9ijWW22V66+pqEpN70ctfX6FSQa4GqhHf60iJ6
|
||||
a1SIursm+PW/vfkcFrsyzF+DE3gTQcm3WxozHYY21PvBj0Ghgem8Vvo2/O+5wahu
|
||||
9APBQITX18SHUJ9lm8gLq5tYE7BqsfFZxV9CX4Dkz98mqZfbhWbM
|
||||
-----END CERTIFICATE-----
|
||||
52
util/tls/testdata/valid_tls.key
vendored
Normal file
52
util/tls/testdata/valid_tls.key
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDkoCvu8Q9uSy6z
|
||||
lV/hJ5FTH9lK+pJDeggsqNhHpMHxKn8IbWNiguiV4gCZ7+j2yg+lD3H9+HMtlS8Q
|
||||
HflgWtwTMvIcDY2XgaVrE4m2DBf3gP/5qW+ywcDbPe7psT2Ms3GkE7PMzSIO4BTO
|
||||
ph9qGQJ1sa5iowCita2j9a55tuNlqe7dFtCtYDpZVDRw+EBLZ0O38gqtg2kLsBCS
|
||||
9s2br2Oe0rzCWEzgGxLaQlLdkPgiQvMX9Gj5/cMDFGaRnIMP5kwGFFeZu5wXyvLG
|
||||
ZaZdnDHcP2PS0FOzKPZISIKosmRNT+OEGBt1Xx4AjW+uQzl3mFBqgatVc8NxiAlc
|
||||
qIIfqj7qco7frbozWssgDbf2CGesGvzt5ug9BK1oo482yBDYFlomWQ5Ximi/lkBQ
|
||||
7eEN5ea8whcBzqxCfExZwDD/SxPPLnuXqnGG6vnPJ/J8VOSM43lI0wuOPkQu4qw0
|
||||
h5xf1CnWb0hn5hGe4ADHh5A/qQaAZERfOE0BBuRqnKgiqxMeMxUwPizqcP15a+ZB
|
||||
Uv92b1So0DFdqnGUtzu6qra5plXshmU84a3jSQguYkE4KOOCJCMGI1yRhum4ejHi
|
||||
5GWjV2CPHs/mZKZ/vViiIWogqPdDycq8JD3/LwCk9X9NwLP2JSYDGnxwduOQP953
|
||||
qAt+g0rJV5/VTpn+EfIK1CwwitCY3QIDAQABAoICAAySklftgb+6+rJ9gGxNVLyR
|
||||
f82Twf9b8p8iGeK2uMOeZqX7/f8o28mCSC4u90y7B+k31Dj3NL5I+fGU9GXMGVYk
|
||||
8xN/2019n68nv+b2+0ptGaaNHsthxE1KNp07Vfsq0xEG1Fhq33iZ8gr7L7cR8QSv
|
||||
5Lsf46UPAKGHnTSsTg0FL1GRM6CVLiBDdS7ROBftcdfnw5aPJ3OxFvg+AkiReJT/
|
||||
WcoGORQJ6Rt/kjcFBeA8dknW8v7saZD9yjYvuTVioMOk0rxtiMP2MSuf42o6cLN/
|
||||
+Ola839ivUh0VFsalFF8FzLocHof5PJ61K1snPhqs+FniBiG6TSRGpKx4ZYEMrlv
|
||||
PAYlk1KytPL78oOiK1vbiXFllmPij0x8p53BgMeih1o92z8xRbgaqF3haXBrhXBa
|
||||
5dyIL747A4PdqOJZA9hm0LQSCQj2NncgdYpDGlHRB7VFBFYfa7ghz+9AIp8wXw9I
|
||||
eamE0n76juJti4zE/HDhov5LeiJNO1hrFK95/3iPKpFrRuzJ5Yl8kcYAWnfVwgO/
|
||||
7eQOkN1Q8hx0+QZf5toiknNxOzUp4DgkGs7Vr7iAwdy5zyQm8apx8IFutniC+xAl
|
||||
qdEnqf8aIfbDEfjvUqbRw/I9un3VDnDIdZwKY3QmjjiNOgM970lhkup62n5cmwSE
|
||||
fsPEaq4AgNOPHlkW2xUBAoIBAQD55OIL96F0toe4/fN/WuKXk62csiyW8YWIqcxY
|
||||
wnZYAK7T92u1sXMsCvCQuSjhhTBIpQKOqzoR7dMSvi6cA09ME30ax0AEGsU1Qqjr
|
||||
/R7KJnQeRd2sHBomTuhSSR31s/kIRdZiOOlfpFduQQaFVrPbKsrmx3DrIQ3aAZtW
|
||||
wRekFlblpp9QZTPL2s/3h2ry4OVEM7yGZfHfJF/DqMynDSeIcnwGkNdEgczvp4SB
|
||||
tKDT4BQ266uJpYLfGkEjRwIMvgqy5QcevvoGeEVM5siFexppSYzw+nJslEqJwF7i
|
||||
vmKuKAQpPXaWVB4HNAlj7ByMgAn6JJCqzbzK6TGZ+k3o5gAxAoIBAQDqNkCSmMiX
|
||||
Zt9MqiDjeXbpCW70tBzc4uFnUcgeJj0j2vmQohHeBwp4YamK8uqhqAV9RAI63sQH
|
||||
XlJQfDDeW7Fq/nys2hTy2GijptMUefmm/tl8HdSsKmLDLcXPeWDpGPqzX576CwOP
|
||||
2xbaF6dX4WOLYcDATS3YTsCZ8RKlXzKyAV1VqKsavz3N14x7isizKFzWmZ37ojuT
|
||||
qCk+vrNA1LNGXAWjPGpFff9mdR/e+ZewsoCUXtvljfv0qtrrdjJg07vGaj7rU9zu
|
||||
xijC2Exlt2RyNVJQMWWU8XqbBn99G3gLtQnHTANB1j4qJ3GMyleD5+7ZaaItJHJ9
|
||||
Yum18IVaTcRtAoIBADH0VE/KH+eB+Z28fmmuFG/yoJkbcRh3jZclQmlX7mpnMIvF
|
||||
AS4gHALo6PA1Y3u5sU5EVj+I8SHWZgRwKkcbzkVJ/A9XV2+6nkOoYLZUMkx85WeL
|
||||
1eVq9LtFuOGCJlAQuy6xL0sRT23EH4o1y4TqMSgV5Nu/cM5AHFHBUnlEPmKZ6KMd
|
||||
7OkYYgNVaY907adB1/MLWJuRU4mk7tPhMZAPbCC1qh9x4uaaAArEdROstR3FxKS5
|
||||
9d+dS40n5W+U6U78yoy6hfLagIa8kjXuSJWOZ1g20Mr3ddpIxqHE5/Lx1i40Z6iK
|
||||
1eL1S89q0pm8AHUBv3zWxGiwmhYCCd1bESoGmHECggEBAM7yqRPflD7TUzO2j+Dv
|
||||
jrZS84udKnOytWBJzv105EkuT54Q1qDMr9+2y8xO4Ct+/3q0ARRrieLI4Qrk8XlI
|
||||
o/fabed9u0zpE2ynF5PcQ0/fl+Qnp6eIvEOhykuNAKh2ve6I6zwdR0RxXjvO8rqg
|
||||
GQkrktlYWM3sqBpd/Q/KkkzfD82Ef8ved4nOj/8JnlVPsNieXA3gR6wsxmT+s/zw
|
||||
9IeTABhAZdaJgobRrxuihvpGf36aYsrvLlX+MfokMleEP0MO1hGxxGHnDlU8MiUe
|
||||
as7PdrANNajpxl/82eF9yBDwInfLHoWp/Lvapma006dl5JKO2BHzRoasQ73TjMFC
|
||||
PfECggEBAMiYSXg/WHPZfiXGUgVHaHeu9j+RoxAN2AVUuQXiaMnor/HsY6/hIsnM
|
||||
23gudabOdQrXzaVh8MWw9Sbxp6SYrFkjowfOLUaCFVUOliLEL2sjD/pfD80hYDM2
|
||||
NfQ6f+7yMOQy+gfvewLQp1icdXRG+9VGu6hLq4jzyCCzHMFT6fvBUv3q/kpKDCCn
|
||||
IuJYp5MMryNVGCscqgSHoneq2IU8lyWBWdB1HLxdea3cTnEpKkrNbGdQzTLC1WhN
|
||||
LlGpWndERNWyjlllYBqL51deZTgtFBl3xpXHWMgWRcYHlwG5YR5QENbyvXplmeXm
|
||||
G8rsta8CWDcRNPNWohci0uq3e7kJvgM=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -10,7 +10,9 @@ import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
@@ -329,3 +331,87 @@ func EncodeX509KeyPairString(cert tls.Certificate) (string, string) {
|
||||
certpem, keypem := EncodeX509KeyPair(cert)
|
||||
return string(certpem), string(keypem)
|
||||
}
|
||||
|
||||
// LoadX509CertPool loads PEM data from a list of files, adds them to a CertPool
|
||||
// and returns the resulting CertPool
|
||||
func LoadX509CertPool(paths ...string) (*x509.CertPool, error) {
|
||||
pool := x509.NewCertPool()
|
||||
for _, path := range paths {
|
||||
log.Infof("Loading CA information from %s and appending it to cert pool", path)
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
// We just ignore non-existing paths...
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
// ...but everything else is considered an error
|
||||
return nil, fmt.Errorf("could not load TLS certificate: %v", err)
|
||||
} else {
|
||||
f, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failure to load TLS certificates from %s: %v", path, err)
|
||||
}
|
||||
if ok := pool.AppendCertsFromPEM(f); !ok {
|
||||
return nil, fmt.Errorf("invalid cert data in %s", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
return pool, 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
|
||||
// the specified list of hosts. If hosts is nil or empty, self-signed cert
|
||||
// creation will be disabled.
|
||||
func CreateServerTLSConfig(tlsCertPath, tlsKeyPath string, hosts []string) (*tls.Config, error) {
|
||||
var cert *tls.Certificate
|
||||
var err error
|
||||
|
||||
tlsCertExists := false
|
||||
tlsKeyExists := false
|
||||
|
||||
// If cert and key paths were specified, ensure they exist
|
||||
if tlsCertPath != "" && tlsKeyPath != "" {
|
||||
_, err = os.Stat(tlsCertPath)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
log.Warnf("could not read TLS cert from %s: %v", tlsCertPath, err)
|
||||
}
|
||||
} else {
|
||||
tlsCertExists = true
|
||||
}
|
||||
|
||||
_, err = os.Stat(tlsKeyPath)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
log.Warnf("could not read TLS cert from %s: %v", tlsKeyPath, err)
|
||||
}
|
||||
} else {
|
||||
tlsKeyExists = true
|
||||
}
|
||||
}
|
||||
|
||||
if !tlsCertExists || !tlsKeyExists {
|
||||
log.Infof("Generating self-signed gRPC TLS certificate for this session")
|
||||
c, err := GenerateX509KeyPair(CertOptions{
|
||||
Hosts: hosts,
|
||||
Organization: "Argo CD",
|
||||
IsCA: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert = c
|
||||
} else {
|
||||
log.Infof("Loading gRPC 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)
|
||||
}
|
||||
cert = &c
|
||||
}
|
||||
|
||||
return &tls.Config{Certificates: []tls.Certificate{*cert}}, nil
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var chain = `-----BEGIN CERTIFICATE-----
|
||||
@@ -341,3 +342,61 @@ func TestBestEffortSystemCertPool(t *testing.T) {
|
||||
pool := BestEffortSystemCertPool()
|
||||
assert.NotNil(t, pool)
|
||||
}
|
||||
|
||||
func TestCreateServerTLSConfig(t *testing.T) {
|
||||
t.Run("Configuration from a valid key/cert pair", func(t *testing.T) {
|
||||
tlsc, err := CreateServerTLSConfig("testdata/valid_tls.crt", "testdata/valid_tls.key", []string{"localhost", "argocd-repo-server"})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, tlsc.Certificates, 1)
|
||||
c, err := x509.ParseCertificate(tlsc.Certificates[0].Certificate[0])
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "SomeCN", c.Subject.CommonName)
|
||||
})
|
||||
|
||||
t.Run("Self-signed creation due to non-existing cert", func(t *testing.T) {
|
||||
tlsc, err := CreateServerTLSConfig("testdata/invvalid_tls.crt", "testdata/invalid_tls.key", []string{"localhost", "argocd-repo-server"})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, tlsc.Certificates, 1)
|
||||
c, err := x509.ParseCertificate(tlsc.Certificates[0].Certificate[0])
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"Argo CD"}, c.Subject.Organization)
|
||||
})
|
||||
|
||||
t.Run("Self-signed creation fails due to hosts being nil", func(t *testing.T) {
|
||||
tlsc, err := CreateServerTLSConfig("testdata/invvalid_tls.crt", "testdata/invalid_tls.key", nil)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, tlsc)
|
||||
})
|
||||
|
||||
t.Run("Self-signed creation fails due to invalid certificates", func(t *testing.T) {
|
||||
tlsc, err := CreateServerTLSConfig("testdata/empty_tls.crt", "testdata/empty_tls.key", nil)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, tlsc)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoadX509CertPool(t *testing.T) {
|
||||
t.Run("Successfully load single cert", func(t *testing.T) {
|
||||
p, err := LoadX509CertPool("testdata/valid_tls.crt")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
assert.Len(t, p.Subjects(), 1)
|
||||
})
|
||||
t.Run("Successfully load single existing cert from multiple list", func(t *testing.T) {
|
||||
p, err := LoadX509CertPool("testdata/invalid_tls.crt", "testdata/valid_tls.crt")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
assert.Len(t, p.Subjects(), 1)
|
||||
})
|
||||
t.Run("Only non-existing certs in list", func(t *testing.T) {
|
||||
p, err := LoadX509CertPool("testdata/invalid_tls.crt", "testdata/valid_tls2.crt")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
assert.Len(t, p.Subjects(), 0)
|
||||
})
|
||||
t.Run("Invalid cert in requested cert list", func(t *testing.T) {
|
||||
p, err := LoadX509CertPool("testdata/empty_tls.crt", "testdata/valid_tls2.crt")
|
||||
require.Error(t, err)
|
||||
require.Nil(t, p)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user