Skip to content

Commit

Permalink
Change Citadel namespace targeting rules
Browse files Browse the repository at this point in the history
Introduce new designated labels ca.istio.io/env and ca.istio.io/override. Check for presence of these options before creating secrets for a
ServiceAccount, and ensure the Citadel instance is in the namespace
designated in the label value or has override label set. The enableNamespacesByDefault option determines the default behavior
in the case that these labels are not found.

Added logic for retroactive creation and deletion of secrets in
activated / deactivated namespaces.
  • Loading branch information
Sam Naser committed Jul 31, 2019
1 parent 1877280 commit bc0b1dc
Show file tree
Hide file tree
Showing 5 changed files with 325 additions and 136 deletions.
Expand Up @@ -71,6 +71,9 @@ spec:
- --liveness-probe-interval=60s # interval for health check file update
- --probe-check-interval=15s # interval for health status check
{{- end }}
env:
- name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT
value: "{{ .Values.enableNamespacesByDefault }}"
{{- if .Values.citadelHealthCheck }}
livenessProbe:
exec:
Expand Down
10 changes: 10 additions & 0 deletions install/kubernetes/helm/istio/charts/security/values.yaml
Expand Up @@ -14,6 +14,16 @@ citadelHealthCheck: false
# 90*24hour = 2160h
workloadCertTtl: 2160h

# Determines Citadel default behavior if the ca.istio.io/env or ca.istio.io/override
# labels are not found on a given namespace.
#
# For example: consider a namespace called "target", which has neither the "ca.istio.io/env"
# nor the "ca.istio.io/override" namespace labels. To decide whether or not to generate secrets
# for service accounts created in this "target" namespace, Citadel will defer to this option. If the value
# of this option is "true" in this case, secrets will be generated for the "target" namespace.
# If the value of this option is "false" Citadel will not generate secrets upon service account creation.
enableNamespacesByDefault: true

# Specify the pod anti-affinity that allows you to constrain which nodes
# your pod is eligible to be scheduled based on labels on pods that are
# already running on the node rather than based on labels on nodes.
Expand Down
31 changes: 19 additions & 12 deletions security/cmd/istio_ca/main.go
Expand Up @@ -48,10 +48,11 @@ import (

type cliOptions struct { // nolint: maligned
// Comma separated string containing all listened namespaces
listenedNamespaces string
istioCaStorageNamespace string
kubeConfigFile string
readSigningCertOnly bool
listenedNamespaces string
enableNamespacesByDefault bool
istioCaStorageNamespace string
kubeConfigFile string
readSigningCertOnly bool

certChainFile string
signingCertFile string
Expand All @@ -61,9 +62,6 @@ type cliOptions struct { // nolint: maligned
selfSignedCA bool
selfSignedCACertTTL time.Duration

// if set, namespaces require explicit labeling to have Citadel generate secrets.
explicitOptInRequired bool

workloadCertTTL time.Duration
maxWorkloadCertTTL time.Duration
// The length of certificate rotation grace period, configured as the ratio of the certificate TTL.
Expand Down Expand Up @@ -152,6 +150,11 @@ func fatalf(template string, args ...interface{}) {
}

func init() {
initCLI()
initEnvVars()
}

func initCLI() {
flags := rootCmd.Flags()
// General configuration.
flags.StringVar(&opts.listenedNamespaces, "listened-namespace", metav1.NamespaceAll, "deprecated")
Expand All @@ -165,9 +168,6 @@ func init() {
cmd.ListenedNamespaceKey+"} environment variable. If neither is set, Citadel listens to all namespaces.")
flags.StringVar(&opts.istioCaStorageNamespace, "citadel-storage-namespace", "istio-system", "Namespace where "+
"the Citadel pod is running. Will not be used if explicit file or other storage mechanism is specified.")
flags.BoolVar(&opts.explicitOptInRequired, "explicit-opt-in", false, "Specifies whether Citadel requires "+
"explicit opt-in for creating secrets. If set, only namespaces labeled with 'istio-managed=enabled' will "+
"have secrets created. This feature is only available in key and certificates delivered through secret volume mount.")

flags.StringVar(&opts.kubeConfigFile, "kube-config", "",
"Specifies path to kubeconfig file. This must be specified when not running inside a Kubernetes pod.")
Expand Down Expand Up @@ -262,6 +262,12 @@ func init() {
cmd.InitializeFlags(rootCmd)
}

func initEnvVars() {
enableNamespacesByDefault := env.RegisterBoolVar("CITADEL_ENABLE_NAMESPACES_BY_DEFAULT", true,
"Determines whether unlabeled namespaces should be targeted by this Citadel instance").Get()
opts.enableNamespacesByDefault = enableNamespacesByDefault
}

func main() {
if err := rootCmd.Execute(); err != nil {
log.Errora(err)
Expand Down Expand Up @@ -312,10 +318,11 @@ func runCA() {
if !opts.serverOnly {
log.Infof("Creating Kubernetes controller to write issued keys and certs into secret ...")
// For workloads in K8s, we apply the configured workload cert TTL.
sc, err := controller.NewSecretController(ca, opts.explicitOptInRequired,
sc, err := controller.NewSecretController(ca,
opts.enableNamespacesByDefault,
opts.workloadCertTTL,
opts.workloadCertGracePeriodRatio, opts.workloadCertMinGracePeriod, opts.dualUse,
cs.CoreV1(), opts.signCACerts, opts.pkcs8Keys, listenedNamespaces, webhooks)
cs.CoreV1(), opts.signCACerts, opts.pkcs8Keys, listenedNamespaces, webhooks, opts.istioCaStorageNamespace)
if err != nil {
fatalf("Failed to create secret controller: %v", err)
}
Expand Down

0 comments on commit bc0b1dc

Please sign in to comment.