From 9e241a74d6c87e43a172129da5b4961ed7e0b172 Mon Sep 17 00:00:00 2001 From: Oliver Gould Date: Wed, 24 Apr 2024 13:55:45 -0700 Subject: [PATCH] feat(inject): Support arbitrary proxy parameters from helm (#12493) New proxy HTTP2 server parameters can be configured from the environment. These environment variables take the form: LINKERD2_PROXY_[INBOUND|OUTBOUND]_[SERVER]_[HTTP2]_ We want to allow these parameters to be set, i.e., in a values.yaml file without having to document all of the possible parameters (especially those that primarily influence internals not exposed to the application). To accomodate this, this commit introduces generic proxy environment templating and a test to verify the behavior. Values like the following: proxy: inbound: scope: proto: blueberryPi: 3.14 outbound: scope: proto: applesauce: "valueA" Manifest as a proxy environment including: LINKERD2_PROXY_INBOUND_SCOPE_PROTO_BLUEBERRY_PI="3.14" LINKERD2_PROXY_OUTBOUND_SCOPE_PROTO_APPLESAUCE=valueA That is, Helm value keys are converted to SCREAMING_SNAKE_CASE environment variable names. --- charts/partials/templates/_proxy.tpl | 11 + cli/cmd/inject_test.go | 28 ++ ...ect_emojivoto_deployment_params.golden.yml | 242 ++++++++++++++++++ pkg/charts/linkerd2/values.go | 7 + 4 files changed, 288 insertions(+) create mode 100644 cli/cmd/testdata/inject_emojivoto_deployment_params.golden.yml diff --git a/charts/partials/templates/_proxy.tpl b/charts/partials/templates/_proxy.tpl index 1db5c8779..103ebb61c 100644 --- a/charts/partials/templates/_proxy.tpl +++ b/charts/partials/templates/_proxy.tpl @@ -104,6 +104,17 @@ env: value: 10000ms - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE value: 10000ms +{{- /* Configure inbound and outbound parameters, e.g. for HTTP/2 servers. */}} +{{ range $proxyK, $proxyV := (dict "inbound" .Values.proxy.inbound "outbound" .Values.proxy.outbound) -}} +{{ range $scopeK, $scopeV := $proxyV -}} +{{ range $protoK, $protoV := $scopeV -}} +{{ range $paramK, $paramV := $protoV -}} +- name: LINKERD2_PROXY_{{snakecase $proxyK | upper}}_{{snakecase $scopeK | upper}}_{{snakecase $protoK | upper}}_{{snakecase $paramK | upper}} + value: {{ quote $paramV }} +{{ end -}} +{{ end -}} +{{ end -}} +{{ end -}} {{ if .Values.proxy.opaquePorts -}} - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION value: {{.Values.proxy.opaquePorts | quote}} diff --git a/cli/cmd/inject_test.go b/cli/cmd/inject_test.go index 6ed75fd8e..910b9eed6 100644 --- a/cli/cmd/inject_test.go +++ b/cli/cmd/inject_test.go @@ -357,6 +357,32 @@ func TestUninjectAndInject(t *testing.T) { return values }(), }, + { + inputFileName: "inject_emojivoto_deployment.input.yml", + goldenFileName: "inject_emojivoto_deployment_params.golden.yml", + reportFileName: "inject_emojivoto_deployment.report", + injectProxy: true, + testInjectConfig: func() *linkerd2.Values { + values := defaultConfig() + values.Proxy.Inbound = linkerd2.ProxyParams{ + "scope": linkerd2.ProxyScopeParams{ + "proto": linkerd2.ProxyProtoParams{ + "appleSauce": "valueA", + "blueberry": 3.14, + }, + }, + } + values.Proxy.Outbound = linkerd2.ProxyParams{ + "scope": linkerd2.ProxyScopeParams{ + "proto": linkerd2.ProxyProtoParams{ + "applesauce": "valueA", + "blueBerry": true, + }, + }, + } + return values + }(), + }, } for i, tc := range testCases { @@ -382,6 +408,8 @@ type injectCmd struct { } func testInjectCmd(t *testing.T, tc injectCmd) { + t.Helper() + testConfig := tc.values if testConfig == nil { var err error diff --git a/cli/cmd/testdata/inject_emojivoto_deployment_params.golden.yml b/cli/cmd/testdata/inject_emojivoto_deployment_params.golden.yml new file mode 100644 index 000000000..26501b96a --- /dev/null +++ b/cli/cmd/testdata/inject_emojivoto_deployment_params.golden.yml @@ -0,0 +1,242 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: web + namespace: emojivoto +spec: + replicas: 1 + selector: + matchLabels: + app: web-svc + template: + metadata: + annotations: + linkerd.io/created-by: linkerd/cli dev-undefined + linkerd.io/proxy-version: test-inject-proxy-version + linkerd.io/trust-root-sha256: 8dc603abd4e755c25c94da05abbf29b9b283a784733651020d72f97ca8ab98e4 + labels: + app: web-svc + linkerd.io/control-plane-ns: linkerd + linkerd.io/proxy-deployment: web + linkerd.io/workload-ns: emojivoto + spec: + containers: + - env: + - name: _pod_name + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: _pod_ns + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: _pod_nodeName + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: LINKERD2_PROXY_LOG + value: warn,linkerd=info,trust_dns=error + - name: LINKERD2_PROXY_LOG_FORMAT + value: plain + - name: LINKERD2_PROXY_DESTINATION_SVC_ADDR + value: linkerd-dst-headless.linkerd.svc.cluster.local.:8086 + - name: LINKERD2_PROXY_DESTINATION_PROFILE_NETWORKS + value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16,fd00::/8 + - name: LINKERD2_PROXY_POLICY_SVC_ADDR + value: linkerd-policy.linkerd.svc.cluster.local.:8090 + - name: LINKERD2_PROXY_POLICY_WORKLOAD + value: | + {"ns":"$(_pod_ns)", "pod":"$(_pod_name)"} + - name: LINKERD2_PROXY_INBOUND_DEFAULT_POLICY + value: all-unauthenticated + - name: LINKERD2_PROXY_POLICY_CLUSTER_NETWORKS + value: 10.0.0.0/8,100.64.0.0/10,172.16.0.0/12,192.168.0.0/16,fd00::/8 + - name: LINKERD2_PROXY_CONTROL_STREAM_INITIAL_TIMEOUT + value: 3s + - name: LINKERD2_PROXY_CONTROL_STREAM_IDLE_TIMEOUT + value: 5m + - name: LINKERD2_PROXY_CONTROL_STREAM_LIFETIME + value: 1h + - name: LINKERD2_PROXY_INBOUND_CONNECT_TIMEOUT + value: 100ms + - name: LINKERD2_PROXY_OUTBOUND_CONNECT_TIMEOUT + value: 1000ms + - name: LINKERD2_PROXY_OUTBOUND_DISCOVERY_IDLE_TIMEOUT + value: 5s + - name: LINKERD2_PROXY_INBOUND_DISCOVERY_IDLE_TIMEOUT + value: 90s + - name: LINKERD2_PROXY_CONTROL_LISTEN_ADDR + value: 0.0.0.0:4190 + - name: LINKERD2_PROXY_ADMIN_LISTEN_ADDR + value: 0.0.0.0:4191 + - name: LINKERD2_PROXY_OUTBOUND_LISTEN_ADDR + value: 127.0.0.1:4140 + - name: LINKERD2_PROXY_INBOUND_LISTEN_ADDR + value: 0.0.0.0:4143 + - name: LINKERD2_PROXY_INBOUND_IPS + valueFrom: + fieldRef: + fieldPath: status.podIPs + - name: LINKERD2_PROXY_INBOUND_PORTS + value: "80" + - name: LINKERD2_PROXY_DESTINATION_PROFILE_SUFFIXES + value: svc.cluster.local. + - name: LINKERD2_PROXY_INBOUND_ACCEPT_KEEPALIVE + value: 10000ms + - name: LINKERD2_PROXY_OUTBOUND_CONNECT_KEEPALIVE + value: 10000ms + - name: LINKERD2_PROXY_INBOUND_SCOPE_PROTO_APPLE_SAUCE + value: valueA + - name: LINKERD2_PROXY_INBOUND_SCOPE_PROTO_BLUEBERRY + value: "3.14" + - name: LINKERD2_PROXY_OUTBOUND_SCOPE_PROTO_APPLESAUCE + value: valueA + - name: LINKERD2_PROXY_OUTBOUND_SCOPE_PROTO_BLUE_BERRY + value: "true" + - name: LINKERD2_PROXY_INBOUND_PORTS_DISABLE_PROTOCOL_DETECTION + value: 25,587,3306,4444,5432,6379,9300,11211 + - name: LINKERD2_PROXY_DESTINATION_CONTEXT + value: | + {"ns":"$(_pod_ns)", "nodeName":"$(_pod_nodeName)", "pod":"$(_pod_name)"} + - name: _pod_sa + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: _l5d_ns + value: linkerd + - name: _l5d_trustdomain + value: cluster.local + - name: LINKERD2_PROXY_IDENTITY_DIR + value: /var/run/linkerd/identity/end-entity + - name: LINKERD2_PROXY_IDENTITY_TRUST_ANCHORS + value: | + -----BEGIN CERTIFICATE----- + MIIBwTCCAWagAwIBAgIQeDZp5lDaIygQ5UfMKZrFATAKBggqhkjOPQQDAjApMScw + JQYDVQQDEx5pZGVudGl0eS5saW5rZXJkLmNsdXN0ZXIubG9jYWwwHhcNMjAwODI4 + MDcxMjQ3WhcNMzAwODI2MDcxMjQ3WjApMScwJQYDVQQDEx5pZGVudGl0eS5saW5r + ZXJkLmNsdXN0ZXIubG9jYWwwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARqc70Z + l1vgw79rjB5uSITICUA6GyfvSFfcuIis7B/XFSkkwAHU5S/s1AAP+R0TX7HBWUC4 + uaG4WWsiwJKNn7mgo3AwbjAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB + /wIBATAdBgNVHQ4EFgQU5YtjVVPfd7I7NLHsn2C26EByGV0wKQYDVR0RBCIwIIIe + aWRlbnRpdHkubGlua2VyZC5jbHVzdGVyLmxvY2FsMAoGCCqGSM49BAMCA0kAMEYC + IQCN7lBFLDDvjx6V0+XkjpKERRsJYf5adMvnloFl48ilJgIhANtxhndcr+QJPuC8 + vgUC0d2/9FMueIVMb+46WTCOjsqr + -----END CERTIFICATE----- + - name: LINKERD2_PROXY_IDENTITY_TOKEN_FILE + value: /var/run/secrets/tokens/linkerd-identity-token + - name: LINKERD2_PROXY_IDENTITY_SVC_ADDR + value: linkerd-identity-headless.linkerd.svc.cluster.local.:8080 + - name: LINKERD2_PROXY_IDENTITY_LOCAL_NAME + value: $(_pod_sa).$(_pod_ns).serviceaccount.identity.linkerd.cluster.local + - name: LINKERD2_PROXY_IDENTITY_SVC_NAME + value: linkerd-identity.linkerd.serviceaccount.identity.linkerd.cluster.local + - name: LINKERD2_PROXY_DESTINATION_SVC_NAME + value: linkerd-destination.linkerd.serviceaccount.identity.linkerd.cluster.local + - name: LINKERD2_PROXY_POLICY_SVC_NAME + value: linkerd-destination.linkerd.serviceaccount.identity.linkerd.cluster.local + image: cr.l5d.io/linkerd/proxy:test-inject-proxy-version + imagePullPolicy: IfNotPresent + lifecycle: + postStart: + exec: + command: + - /usr/lib/linkerd/linkerd-await + - --timeout=2m + - --port=4191 + livenessProbe: + httpGet: + path: /live + port: 4191 + initialDelaySeconds: 10 + timeoutSeconds: 1 + name: linkerd-proxy + ports: + - containerPort: 4143 + name: linkerd-proxy + - containerPort: 4191 + name: linkerd-admin + readinessProbe: + httpGet: + path: /ready + port: 4191 + initialDelaySeconds: 2 + timeoutSeconds: 1 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 2102 + seccompProfile: + type: RuntimeDefault + terminationMessagePolicy: FallbackToLogsOnError + volumeMounts: + - mountPath: /var/run/linkerd/identity/end-entity + name: linkerd-identity-end-entity + - mountPath: /var/run/secrets/tokens + name: linkerd-identity-token + - env: + - name: WEB_PORT + value: "80" + - name: EMOJISVC_HOST + value: emoji-svc.emojivoto:8080 + - name: VOTINGSVC_HOST + value: voting-svc.emojivoto:8080 + - name: INDEX_BUNDLE + value: dist/index_bundle.js + image: buoyantio/emojivoto-web:v10 + name: web-svc + ports: + - containerPort: 80 + name: http + initContainers: + - args: + - --incoming-proxy-port + - "4143" + - --outgoing-proxy-port + - "4140" + - --proxy-uid + - "2102" + - --inbound-ports-to-ignore + - 4190,4191,4567,4568 + - --outbound-ports-to-ignore + - 4567,4568 + image: cr.l5d.io/linkerd/proxy-init:v2.4.0 + imagePullPolicy: IfNotPresent + name: linkerd-init + resources: + limits: + cpu: 100m + memory: 20Mi + requests: + cpu: 100m + memory: 20Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_ADMIN + - NET_RAW + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 65534 + seccompProfile: + type: RuntimeDefault + terminationMessagePolicy: FallbackToLogsOnError + volumeMounts: + - mountPath: /run + name: linkerd-proxy-init-xtables-lock + volumes: + - emptyDir: {} + name: linkerd-proxy-init-xtables-lock + - emptyDir: + medium: Memory + name: linkerd-identity-end-entity + - name: linkerd-identity-token + projected: + sources: + - serviceAccountToken: + audience: identity.l5d.io + expirationSeconds: 86400 + path: linkerd-identity-token +--- diff --git a/pkg/charts/linkerd2/values.go b/pkg/charts/linkerd2/values.go index f1fa43ac6..b43f029aa 100644 --- a/pkg/charts/linkerd2/values.go +++ b/pkg/charts/linkerd2/values.go @@ -139,8 +139,15 @@ type ( AdditionalEnv []corev1.EnvVar `json:"additionalEnv"` ExperimentalEnv []corev1.EnvVar `json:"experimentalEnv"` + + Inbound ProxyParams `json:"inbound,omitempty"` + Outbound ProxyParams `json:"outbound,omitempty"` } + ProxyParams = map[string]ProxyScopeParams + ProxyScopeParams = map[string]ProxyProtoParams + ProxyProtoParams = map[string]interface{} + ProxyControl struct { Streams *ProxyControlStreams `json:"streams"` }