diff --git a/api/v1alpha1/argocd_conversion.go b/api/v1alpha1/argocd_conversion.go index 64270ff43..591924240 100644 --- a/api/v1alpha1/argocd_conversion.go +++ b/api/v1alpha1/argocd_conversion.go @@ -45,7 +45,7 @@ func (src *ArgoCD) ConvertTo(dstRaw conversion.Hub) error { sso = &v1beta1.ArgoCDSSOSpec{} } sso.Provider = v1beta1.SSOProviderTypeDex - sso.Dex = (*v1beta1.ArgoCDDexSpec)(src.Spec.Dex) + sso.Dex = ConvertAlphaToBetaDex(src.Spec.Dex) } dst.Spec.SSO = sso @@ -244,13 +244,29 @@ func ConvertAlphaToBetaSSO(src *ArgoCDSSOSpec) *v1beta1.ArgoCDSSOSpec { if src != nil { dst = &v1beta1.ArgoCDSSOSpec{ Provider: v1beta1.SSOProviderType(src.Provider), - Dex: (*v1beta1.ArgoCDDexSpec)(src.Dex), + Dex: ConvertAlphaToBetaDex(src.Dex), Keycloak: (*v1beta1.ArgoCDKeycloakSpec)(src.Keycloak), } } return dst } +func ConvertAlphaToBetaDex(src *ArgoCDDexSpec) *v1beta1.ArgoCDDexSpec { + var dst *v1beta1.ArgoCDDexSpec + if src != nil { + dst = &v1beta1.ArgoCDDexSpec{ + Config: src.Config, + Groups: src.Groups, + Image: src.Image, + OpenShiftOAuth: src.OpenShiftOAuth, + Resources: src.Resources, + Version: src.Version, + Env: nil, + } + } + return dst +} + func ConvertAlphaToBetaHA(src *ArgoCDHASpec) *v1beta1.ArgoCDHASpec { var dst *v1beta1.ArgoCDHASpec if src != nil { @@ -448,13 +464,28 @@ func ConvertBetaToAlphaSSO(src *v1beta1.ArgoCDSSOSpec) *ArgoCDSSOSpec { if src != nil { dst = &ArgoCDSSOSpec{ Provider: SSOProviderType(src.Provider), - Dex: (*ArgoCDDexSpec)(src.Dex), + Dex: ConvertBetaToAlphaDex(src.Dex), Keycloak: (*ArgoCDKeycloakSpec)(src.Keycloak), } } return dst } +func ConvertBetaToAlphaDex(src *v1beta1.ArgoCDDexSpec) *ArgoCDDexSpec { + var dst *ArgoCDDexSpec + if src != nil { + dst = &ArgoCDDexSpec{ + Config: src.Config, + Groups: src.Groups, + Image: src.Image, + OpenShiftOAuth: src.OpenShiftOAuth, + Resources: src.Resources, + Version: src.Version, + } + } + return dst +} + func ConvertBetaToAlphaHA(src *v1beta1.ArgoCDHASpec) *ArgoCDHASpec { var dst *ArgoCDHASpec if src != nil { diff --git a/api/v1beta1/argocd_types.go b/api/v1beta1/argocd_types.go index 5c55851f4..7a401eba4 100644 --- a/api/v1beta1/argocd_types.go +++ b/api/v1beta1/argocd_types.go @@ -203,6 +203,9 @@ type ArgoCDDexSpec struct { // Version is the Dex container image tag. //+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:Dex","urn:alm:descriptor:com.tectonic.ui:text"} Version string `json:"version,omitempty"` + + // Env lets you specify environment variables for Dex. + Env []corev1.EnvVar `json:"env,omitempty"` } // ArgoCDGrafanaSpec defines the desired state for the Grafana component. diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 864d81bca..cf6ca277c 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -202,6 +202,13 @@ func (in *ArgoCDDexSpec) DeepCopyInto(out *ArgoCDDexSpec) { *out = new(v1.ResourceRequirements) (*in).DeepCopyInto(*out) } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoCDDexSpec. diff --git a/bundle/manifests/argoproj.io_argocds.yaml b/bundle/manifests/argoproj.io_argocds.yaml index e8ba59f6c..82cd8b2ad 100644 --- a/bundle/manifests/argoproj.io_argocds.yaml +++ b/bundle/manifests/argoproj.io_argocds.yaml @@ -13474,6 +13474,121 @@ spec: config: description: Config is the dex connector configuration. type: string + env: + description: Env lets you specify environment variables for + Dex. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array groups: description: Optional list of required groups a user must be a member of diff --git a/config/crd/bases/argoproj.io_argocds.yaml b/config/crd/bases/argoproj.io_argocds.yaml index 51f836e37..98a1c8fdc 100644 --- a/config/crd/bases/argoproj.io_argocds.yaml +++ b/config/crd/bases/argoproj.io_argocds.yaml @@ -13465,6 +13465,121 @@ spec: config: description: Config is the dex connector configuration. type: string + env: + description: Env lets you specify environment variables for + Dex. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array groups: description: Optional list of required groups a user must be a member of diff --git a/controllers/argocd/dex.go b/controllers/argocd/dex.go index 916b84aa3..fdc7704c0 100644 --- a/controllers/argocd/dex.go +++ b/controllers/argocd/dex.go @@ -133,7 +133,6 @@ func (r *ReconcileArgoCD) reconcileDexConfiguration(cm *corev1.ConfigMap, cr *ar // getOpenShiftDexConfig will return the configuration for the Dex server running on OpenShift. func (r *ReconcileArgoCD) getOpenShiftDexConfig(cr *argoproj.ArgoCD) (string, error) { - groups := []string{} // Allow override of groups from CR @@ -167,7 +166,6 @@ func (r *ReconcileArgoCD) getOpenShiftDexConfig(cr *argoproj.ArgoCD) (string, er // reconcileDexServiceAccount will ensure that the Dex ServiceAccount is configured properly for OpenShift OAuth. func (r *ReconcileArgoCD) reconcileDexServiceAccount(cr *argoproj.ArgoCD) error { - // if openShiftOAuth set to false in `.spec.sso.dex`, no need to configure it if cr.Spec.SSO == nil || cr.Spec.SSO.Dex == nil || !cr.Spec.SSO.Dex.OpenShiftOAuth { return nil // OpenShift OAuth not enabled, move along... @@ -207,6 +205,11 @@ func (r *ReconcileArgoCD) reconcileDexDeployment(cr *argoproj.ArgoCD) error { AddSeccompProfileForOpenShift(r.Client, &deploy.Spec.Template.Spec) + dexEnv := proxyEnvVars() + if cr.Spec.SSO != nil && cr.Spec.SSO.Dex != nil { + dexEnv = append(dexEnv, cr.Spec.SSO.Dex.Env...) + } + deploy.Spec.Template.Spec.Containers = []corev1.Container{{ Command: []string{ "/shared/argocd-dex", @@ -214,7 +217,7 @@ func (r *ReconcileArgoCD) reconcileDexDeployment(cr *argoproj.ArgoCD) error { }, Image: getDexContainerImage(cr), Name: "dex", - Env: proxyEnvVars(), + Env: dexEnv, LivenessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ @@ -397,7 +400,6 @@ func (r *ReconcileArgoCD) reconcileDexService(cr *argoproj.ArgoCD) error { // reconcileDexResources consolidates all dex resources reconciliation calls. It serves as the single place to trigger both creation // and deletion of dex resources based on the specified configuration of dex func (r *ReconcileArgoCD) reconcileDexResources(cr *argoproj.ArgoCD) error { - if _, err := r.reconcileRole(common.ArgoCDDexServerComponent, policyRuleForDexServer(), cr); err != nil { log.Error(err, "error reconciling dex role") } @@ -441,7 +443,6 @@ func (r *ReconcileArgoCD) reconcileDexResources(cr *argoproj.ArgoCD) error { // Deployment and RoleBinding must be deleted before the role and sa. deleteDexResources will only be called during // delete events, so we don't need to worry about duplicate, recurring reconciliation calls func (r *ReconcileArgoCD) deleteDexResources(cr *argoproj.ArgoCD) error { - sa := &corev1.ServiceAccount{} role := &rbacv1.Role{} diff --git a/controllers/argocd/dex_test.go b/controllers/argocd/dex_test.go index 7c7acf74c..3f0ca40a2 100644 --- a/controllers/argocd/dex_test.go +++ b/controllers/argocd/dex_test.go @@ -332,7 +332,8 @@ func TestReconcileArgoCD_reconcileDexDeployment(t *testing.T) { RunAsNonRoot: boolPtr(true), }, VolumeMounts: []corev1.VolumeMount{ - {Name: "static-files", MountPath: "/shared"}}, + {Name: "static-files", MountPath: "/shared"}, + }, }, }, ServiceAccountName: "argocd-argocd-dex-server", @@ -344,92 +345,6 @@ func TestReconcileArgoCD_reconcileDexDeployment(t *testing.T) { func TestReconcileArgoCD_reconcileDexDeployment_withUpdate(t *testing.T) { logf.SetLogger(ZapLogger(true)) - desiredPodSpec := corev1.PodSpec{ - Volumes: []corev1.Volume{ - { - Name: "static-files", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, - }, - InitContainers: []corev1.Container{ - { - Name: "copyutil", - Image: "justatest:latest", - Command: []string{ - "cp", - "-n", - "/usr/local/bin/argocd", - "/shared/argocd-dex", - }, - SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: boolPtr(false), - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - RunAsNonRoot: boolPtr(true), - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "static-files", - MountPath: "/shared", - }, - }, - ImagePullPolicy: corev1.PullAlways, - }, - }, - Containers: []corev1.Container{ - { - Name: "dex", - Image: "testdex:v0.0.1", - Command: []string{ - "/shared/argocd-dex", - "rundex", - }, - LivenessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/healthz/live", - Port: intstr.FromInt(5558), - }, - }, - InitialDelaySeconds: 60, - PeriodSeconds: 30, - }, - Ports: []corev1.ContainerPort{ - { - Name: "http", - ContainerPort: 5556, - }, - { - Name: "grpc", - ContainerPort: 5557, - }, - { - Name: "metrics", - ContainerPort: 5558, - }, - }, - SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: boolPtr(false), - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - RunAsNonRoot: boolPtr(true), - }, - VolumeMounts: []corev1.VolumeMount{ - {Name: "static-files", MountPath: "/shared"}}, - }, - }, - ServiceAccountName: "argocd-argocd-dex-server", - NodeSelector: common.DefaultNodeSelector(), - } - tests := []struct { name string setEnvFunc func(*testing.T, string) @@ -459,7 +374,218 @@ func TestReconcileArgoCD_reconcileDexDeployment_withUpdate(t *testing.T) { }, } }), - wantPodSpec: desiredPodSpec, + wantPodSpec: corev1.PodSpec{ + Volumes: []corev1.Volume{ + { + Name: "static-files", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }, + InitContainers: []corev1.Container{ + { + Name: "copyutil", + Image: "justatest:latest", + Command: []string{ + "cp", + "-n", + "/usr/local/bin/argocd", + "/shared/argocd-dex", + }, + SecurityContext: &corev1.SecurityContext{ + AllowPrivilegeEscalation: boolPtr(false), + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + RunAsNonRoot: boolPtr(true), + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "static-files", + MountPath: "/shared", + }, + }, + ImagePullPolicy: corev1.PullAlways, + }, + }, + Containers: []corev1.Container{ + { + Name: "dex", + Image: "testdex:v0.0.1", + Command: []string{ + "/shared/argocd-dex", + "rundex", + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/healthz/live", + Port: intstr.FromInt(5558), + }, + }, + InitialDelaySeconds: 60, + PeriodSeconds: 30, + }, + Ports: []corev1.ContainerPort{ + { + Name: "http", + ContainerPort: 5556, + }, + { + Name: "grpc", + ContainerPort: 5557, + }, + { + Name: "metrics", + ContainerPort: 5558, + }, + }, + SecurityContext: &corev1.SecurityContext{ + AllowPrivilegeEscalation: boolPtr(false), + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + RunAsNonRoot: boolPtr(true), + }, + VolumeMounts: []corev1.VolumeMount{ + {Name: "static-files", MountPath: "/shared"}, + }, + }, + }, + ServiceAccountName: "argocd-argocd-dex-server", + NodeSelector: common.DefaultNodeSelector(), + }, + }, + { + name: "update dex deployment - .spec.sso.dex.env", + setEnvFunc: nil, + updateCrFunc: func(cr *argoproj.ArgoCD) { + cr.Spec.SSO.Dex.Env = []corev1.EnvVar{ + { + Name: "ARGO_WORKFLOWS_SSO_CLIENT_SECRET", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "argo-workflows-sso", + }, + Key: "client-secret", + }, + }, + }, + } + }, + argoCD: makeTestArgoCD(func(cr *argoproj.ArgoCD) { + cr.Spec.SSO = &argoproj.ArgoCDSSOSpec{ + Provider: argoproj.SSOProviderTypeDex, + Dex: &argoproj.ArgoCDDexSpec{ + OpenShiftOAuth: true, + }, + } + }), + wantPodSpec: corev1.PodSpec{ + Volumes: []corev1.Volume{ + { + Name: "static-files", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }, + InitContainers: []corev1.Container{ + { + Name: "copyutil", + Image: "quay.io/argoproj/argocd@sha256:d40da8f5747415eb7f9b5c2d9b645aecd423888cad9b36e4f986bff8ecf0a786", + Command: []string{ + "cp", + "-n", + "/usr/local/bin/argocd", + "/shared/argocd-dex", + }, + SecurityContext: &corev1.SecurityContext{ + AllowPrivilegeEscalation: boolPtr(false), + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + RunAsNonRoot: boolPtr(true), + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "static-files", + MountPath: "/shared", + }, + }, + ImagePullPolicy: corev1.PullAlways, + }, + }, + Containers: []corev1.Container{ + { + Name: "dex", + Image: "ghcr.io/dexidp/dex@sha256:d5f887574312f606c61e7e188cfb11ddb33ff3bf4bd9f06e6b1458efca75f604", + Command: []string{ + "/shared/argocd-dex", + "rundex", + }, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/healthz/live", + Port: intstr.FromInt(5558), + }, + }, + InitialDelaySeconds: 60, + PeriodSeconds: 30, + }, + Ports: []corev1.ContainerPort{ + { + Name: "http", + ContainerPort: 5556, + }, + { + Name: "grpc", + ContainerPort: 5557, + }, + { + Name: "metrics", + ContainerPort: 5558, + }, + }, + Env: []corev1.EnvVar{ + { + Name: "ARGO_WORKFLOWS_SSO_CLIENT_SECRET", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "argo-workflows-sso", + }, + Key: "client-secret", + }, + }, + }, + }, + SecurityContext: &corev1.SecurityContext{ + AllowPrivilegeEscalation: boolPtr(false), + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + RunAsNonRoot: boolPtr(true), + }, + VolumeMounts: []corev1.VolumeMount{ + {Name: "static-files", MountPath: "/shared"}, + }, + }, + }, + ServiceAccountName: "argocd-argocd-dex-server", + NodeSelector: common.DefaultNodeSelector(), + }, }, } diff --git a/deploy/olm-catalog/argocd-operator/0.8.0/argoproj.io_argocds.yaml b/deploy/olm-catalog/argocd-operator/0.8.0/argoproj.io_argocds.yaml index e8ba59f6c..82cd8b2ad 100644 --- a/deploy/olm-catalog/argocd-operator/0.8.0/argoproj.io_argocds.yaml +++ b/deploy/olm-catalog/argocd-operator/0.8.0/argoproj.io_argocds.yaml @@ -13474,6 +13474,121 @@ spec: config: description: Config is the dex connector configuration. type: string + env: + description: Env lets you specify environment variables for + Dex. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables + in the container and any service environment variables. + If a variable cannot be resolved, the reference in + the input string will be unchanged. Double $$ are + reduced to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce + the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the + variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array groups: description: Optional list of required groups a user must be a member of diff --git a/docs/reference/argocd.md b/docs/reference/argocd.md index 4bb5f1b74..0c7e8d2f1 100644 --- a/docs/reference/argocd.md +++ b/docs/reference/argocd.md @@ -104,7 +104,7 @@ spec: ### Add Command Arguments to ApplicationSets Controller -Below example shows how a user can add command arguments to the ApplicationSet controller. +Below example shows how a user can add command arguments to the ApplicationSet controller. ``` yaml apiVersion: argoproj.io/v1alpha1 @@ -137,7 +137,6 @@ spec: SCMRootCAConfigMap: example-gitlab-scm-tls-cert ``` - ## Config Management Plugins Configuration to add a config management plugin. This property maps directly to the `configManagementPlugins` field in the `argocd-cm` ConfigMap. @@ -200,7 +199,7 @@ spec: resources: {} ``` -The following example shows how to set command line parameters using the env variable +The following example shows how to set command line parameters using the env variable ``` yaml apiVersion: argoproj.io/v1alpha1 @@ -213,7 +212,7 @@ spec: controller: env: - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS - value: '120' + value: '120' ``` The following example shows how to set multiple replicas of Argo CD Application Controller. This example will scale up/down the Argo CD Application Controller based on the parameter clustersPerShard. The number of replicas will be set between minShards and maxShards. @@ -237,7 +236,6 @@ spec: !!! note In case the number of replicas required is less than the minShards the number of replicas will be set as minShards. Similarly, if the required number of replicas exceeds maxShards, the replica count will be set as maxShards. - The following example shows how to enable dynamic scaling of the ArgoCD Application Controller component. ```yaml @@ -757,10 +755,10 @@ metadata: labels: example: nodeplacement-example spec: - nodePlacement: - nodeSelector: + nodePlacement: + nodeSelector: key1: value1 - tolerations: + tolerations: - key: key1 operator: Equal value: value1 @@ -768,7 +766,7 @@ spec: - key: key1 operator: Equal value: value1 - effect: NoExecute + effect: NoExecute ``` ## Prometheus Options @@ -965,7 +963,7 @@ spec: Resource behavior can be customized using subkeys (`resourceHealthChecks`, `resourceIgnoreDifferences`, and `resourceActions`). Each of the subkeys maps directly to their own field in the `argocd-cm`. `resourceHealthChecks` will map to `resource.customizations.health`, `resourceIgnoreDifferences` to `resource.customizations.ignoreDifferences`, and `resourceActions` to `resource.customizations.actions`. -!!! note +!!! note `.spec.resourceCustomizations` field is no longer in support from Argo CD Operator v0.8.0 onward. Consider using `resourceHealthChecks`, `resourceIgnoreDifferences`, and `resourceActions` instead. ### Resource Customizations (with subkeys) @@ -1058,7 +1056,7 @@ spec: return obj ``` -After applying these changes your `argocd-cm` Configmap should contain the following fields: +After applying these changes your `argocd-cm` Configmap should contain the following fields: ``` resource.customizations.ignoreDifferences.apps_Deployment: | @@ -1148,7 +1146,7 @@ spec: - /spec/replicas ``` -After applying these changes your `argocd-cm` Configmap should contain the following fields: +After applying these changes your `argocd-cm` Configmap should contain the following fields: ``` resource.customizations.ignoreDifferences.admissionregistration.k8s.io_MutatingWebhookConfiguration: | @@ -1227,7 +1225,7 @@ spec: ## Resource Tracking Method -You can configure which +You can configure which [resource tracking method](https://argo-cd.readthedocs.io/en/stable/user-guide/resource_tracking/#choosing-a-tracking-method) Argo CD should use to keep track of the resources it manages. @@ -1286,7 +1284,7 @@ Enabled | false | Toggle Autoscaling support globally for the Argo CD server com HPA | [Object] | HorizontalPodAutoscaler options for the Argo CD Server component. !!! note - When `.spec.server.autoscale.enabled` is set to `true`, the number of required replicas (if set) in `.spec.server.replicas` will be ignored. The final replica count on the server deployment will be controlled by the Horizontal Pod Autoscaler instead. + When `.spec.server.autoscale.enabled` is set to `true`, the number of required replicas (if set) in `.spec.server.replicas` will be ignored. The final replica count on the server deployment will be controlled by the Horizontal Pod Autoscaler instead. ### Server Command Arguments @@ -1449,13 +1447,14 @@ Image | `quay.io/dexidp/dex` | The container image for Dex. This overrides the ` OpenShiftOAuth | false | Enable automatic configuration of OpenShift OAuth authentication for the Dex server. This is ignored if a value is present for `sso.dex.config`. Resources | [Empty] | The container compute resources. Version | v2.21.0 (SHA) | The tag to use with the Dex container image. +Env | [Empty] | Environment to set for Dex. ### Dex Example !!! note `.spec.dex` is no longer supported in Argo CD operator v0.8.0 onwards, use `.spec.sso.dex` instead. -The following examples show all properties set to the default values. +The following examples show all properties set to the default values. ``` yaml apiVersion: argoproj.io/v1alpha1 @@ -1506,7 +1505,7 @@ spec: ### Important Note regarding Role Mappings: -To have a specific user be properly atrributed with the `role:admin` upon SSO through Openshift, the user needs to be in a **group** with the `cluster-admin` role added. If the user only has a direct `ClusterRoleBinding` to the Openshift role for `cluster-admin`, the ArgoCD role will not map. +To have a specific user be properly atrributed with the `role:admin` upon SSO through Openshift, the user needs to be in a **group** with the `cluster-admin` role added. If the user only has a direct `ClusterRoleBinding` to the Openshift role for `cluster-admin`, the ArgoCD role will not map. A quick fix will be to create an `cluster-admins` group, add the user to the group and then apply the `cluster-admin` ClusterRole to the group. @@ -1675,7 +1674,7 @@ spec: ## Banner -The following properties are available for configuring a [UI banner message](https://argo-cd.readthedocs.io/en/stable/operator-manual/custom-styles/#banners). +The following properties are available for configuring a [UI banner message](https://argo-cd.readthedocs.io/en/stable/operator-manual/custom-styles/#banners). Name | Default | Description --- | --- | --- diff --git a/docs/usage/dex.md b/docs/usage/dex.md index 172900487..c20b207a1 100644 --- a/docs/usage/dex.md +++ b/docs/usage/dex.md @@ -11,13 +11,13 @@ Dex can be used to delegate authentication to external identity providers like G ## Installing & Configuring Dex -Dex configuration has moved to `.spec.sso` in release v0.4.0. Dex can be enabled by setting `.spec.sso.provider` to `dex` in the Argo CD CR. +Dex configuration has moved to `.spec.sso` in release v0.4.0. Dex can be enabled by setting `.spec.sso.provider` to `dex` in the Argo CD CR. !!! note - It is now mandatory to specify `.spec.sso.dex` either with OpenShift configuration through `openShiftOAuth: true` or valid custom configuration supplied through `.spec.sso.dex.config`. Absence of either will result in an error due to failing health checks on Dex. + It is now mandatory to specify `.spec.sso.dex` either with OpenShift configuration through `openShiftOAuth: true` or valid custom configuration supplied through `.spec.sso.dex.config`. Absence of either will result in an error due to failing health checks on Dex. !!! note - Specifying `.spec.sso.dex` without setting dex as the provider will result in an error. + Specifying `.spec.sso.dex` without setting dex as the provider will result in an error. !!! note `.spec.dex` is no longer supported in Argo CD operator v0.8.0 onwards, use `.spec.sso.dex` instead. @@ -111,9 +111,47 @@ spec: - name: dummy-org ``` -## Uninstalling Dex +## Use ArgoCD's Dex for Argo Workflows authentication + +The below section describes how to configure Argo CD's Dex to accept authentication requests from Argo Workflows. + +1. Register the application in the identity provider as explained [here](https://argoproj.github.io/argo-cd/operator-manual/user-management/#1-register-the-application-in-the-identity-provider). + +2. Update the Argo CD CR. + +In the `sso.dex.env` key, add the environment variable as shown in the [example manifests for authenticating against Argo CD's Dex](https://argoproj.github.io/argo-workflows/argo-server-sso-argocd/#example-manifests-for-authenticating-against-argo-cds-dex-kustomize). + +``` yaml +apiVersion: argoproj.io/v1alpha1 +kind: ArgoCD +metadata: + name: example-argocd +spec: + sso: + provider: dex + dex: + config: | + connectors: + # GitHub example + - type: github + id: github + name: GitHub + config: + clientID: xxxxxxxxxxxxxx + clientSecret: $dex.github.clientSecret # Alternatively $:dex.github.clientSecret + orgs: + - name: dummy-org + env: + - name: ARGO_WORKFLOWS_SSO_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: argo-workflows-sso + key: client-secret +``` + +## Uninstalling Dex !!! note `DISABLE_DEX` environment variable is no longer supported in Argo CD operator v0.8.0 onwards. -Dex can be uninstalled either by removing `.spec.sso` from the Argo CD CR, or switching to a different SSO provider. +Dex can be uninstalled either by removing `.spec.sso` from the Argo CD CR, or switching to a different SSO provider. diff --git a/tests/k8s/1-015_validate_sso_status/06-assert.yaml b/tests/k8s/1-015_validate_sso_status/06-assert.yaml new file mode 100644 index 000000000..8ee9d232a --- /dev/null +++ b/tests/k8s/1-015_validate_sso_status/06-assert.yaml @@ -0,0 +1,36 @@ +apiVersion: argoproj.io/v1beta1 +kind: ArgoCD +metadata: + name: argocd +spec: + sso: + provider: dex + dex: + config: test-config + env: + - name: ARGO_WORKFLOWS_SSO_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: argo-workflows-sso + key: client-secret +status: + phase: Available + sso: Running +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argocd-dex-server +spec: + template: + spec: + containers: + - name: dex + env: + - name: ARGO_WORKFLOWS_SSO_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: argo-workflows-sso + key: client-secret +status: + readyReplicas: 1 diff --git a/tests/k8s/1-015_validate_sso_status/06-dex-spec-sso-env.yaml b/tests/k8s/1-015_validate_sso_status/06-dex-spec-sso-env.yaml new file mode 100644 index 000000000..dcb2224a2 --- /dev/null +++ b/tests/k8s/1-015_validate_sso_status/06-dex-spec-sso-env.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Secret +metadata: + name: argo-workflows-sso +data: + client-id: YXJnby13b3JrZmxvd3Mtc3Nv + client-secret: aGk= +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # Patches to add dex as an sso provider and configure the environment variables. + - script: | + kubectl patch -n $NAMESPACE argocd/argocd --type='json' -p='[{"op":"add","path":"/spec/sso","value":{}},{"op":"add","path":"/spec/sso/provider","value":"dex"},{"op":"add","path":"/spec/sso/dex","value":{}},{"op":"add","path":"/spec/sso/dex/config","value":"test-config"},{"op":"add","path":"/spec/sso/dex/env","value":[]},{"op":"add","path":"/spec/sso/dex/env/0","value":{"name":"ARGO_WORKFLOWS_SSO_CLIENT_SECRET","valueFrom":{"secretKeyRef":{"name":"argo-workflows-sso","key":"client-secret"}}}}]' + - script: sleep 10