Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Introduce value to run proxy-init as privileged #9873

Merged
merged 4 commits into from
Nov 25, 2022

Conversation

mateiidavid
Copy link
Member

This change aims to solve two distinct issues that have cropped up in the proxy-init configuration.

First, it decouples allowPrivilegeEscalation from running proxy-init as root. At the moment, whenever the container is run as root, privilege escalation is also allowed. In more restrictive environments, this will prevent the pod from coming up (e.g security policies may complain about allowPrivilegeEscalation=true). Worth noting that privilege escalation is not necessary in many scenarios since the capabilities are passed to the iptables child process at build time.

Second, it introduces a new privileged value that will allow users to run the proxy-init container without any restrictions (meaning all capabilities are inherited). This is essentially the same as mapping root on host to root in the container. This value may solve issues in distributions that run security enhanced linux, since iptables will be able to load kernel modules that it may otherwise not be able to load (privileged mode allows the container nearly the same privileges as processes running outside of a container on a host, this further allows the container to set configurations in AppArmor or SELinux).

Privileged mode is independent from running the container as root. This gives users more control over the security context in proxy-init. The value may still be used with runAsRoot: false.

Fixes #9718

Signed-off-by: Matei David matei@buoyant.io


Relevant literature:

My hunch is that coupled with SELinux options at a Pod level, this should also fix #7767


Tests

I tested only with the control plane which makes use of the proxy-init partial. I tested four distinct scenarios:

  1. Default (privileged=false, runAsRoot=false)
  2. Privileged-only (privileged=true)
  3. Privileged and root (privileged=true, runAsRoot=true)
  4. Root only (privileged=false, runAsRoot=true)

I tested that the pods are running and we see what we are supposed to in the security context. All yaml output is taken from the destination pod in all 4 cases.

:; kgp -n linkerd
NAME                                      READY   STATUS    RESTARTS   AGE
linkerd-identity-b578dcd7-wzfft           2/2     Running   0          8m12s
linkerd-destination-77858c7cdf-4t84d      4/4     Running   0          8m12s
linkerd-proxy-injector-8467f465d9-m2hrg   2/2     Running   0          8m12s

    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
      privileged: false
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      runAsUser: 65534
    terminationMessagePath: /dev/termination-log

:; kgp -n linkerd
NAME                                      READY   STATUS    RESTARTS   AGE
linkerd-identity-b5b966fc8-pw55t          2/2     Running   0          66s
linkerd-destination-5797b48dd6-dx829      4/4     Running   0          66s
linkerd-proxy-injector-6b77c67598-jcgld   2/2     Running   0          66s

    securityContext:
      allowPrivilegeEscalation: true
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
      privileged: true
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      runAsUser: 65534
    terminationMessagePath: /dev/termination-log

:; kgp -n linkerd
NAME                                      READY   STATUS    RESTARTS   AGE
linkerd-identity-5cfbcd6bbd-w4gvf         2/2     Running   0          66s
linkerd-destination-57799fc85d-mb6kq      4/4     Running   0          66s
linkerd-proxy-injector-7446c779cb-sc7pv   2/2     Running   0          66s

    securityContext:
      allowPrivilegeEscalation: true
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
      privileged: true
      readOnlyRootFilesystem: true
      runAsNonRoot: false
      runAsUser: 0
    terminationMessagePath: /dev/termination-log
:; kgp -n linkerd
NAME                                      READY   STATUS    RESTARTS   AGE
linkerd-identity-759d77d5c4-9vnfw         2/2     Running   0          62s
linkerd-destination-5f997cdf64-jbkp8      4/4     Running   0          62s
linkerd-proxy-injector-6465df8b58-4k9hq   2/2     Running   0          62s


    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
      privileged: false
      readOnlyRootFilesystem: true
      runAsNonRoot: false
      runAsUser: 0
    terminationMessagePath: /dev/termination-log

This change aims to solve two distinct issues that have cropped up in
the proxy-init configuration.

First, it decouples `allowPrivilegeEscalation` from running proxy-init
as root. At the moment, whenever the container is run as root, privilege
escalation is also allowed. In more restrictive environments, this will
prevent the pod from coming up (e.g security policies may complain about
`allowPrivilegeEscalation=true`). Worth noting that privilege escalation
is not necessary in many scenarios since the capabilities are passed to
the iptables child process at build time.

Second, it introduces a new `privileged` value that will allow users to
run the proxy-init container without any restrictions (meaning all
capabilities are inherited). This is essentially the same as mapping
root on host to root in the container. This value may solve issues in
distributions that run security enhanced linux, since iptables will be
able to load kernel modules that it may otherwise not be able to load
(privileged mode allows the container nearly the same privileges as
processes running outside of a container on a host, this further allows
the container to set configurations in AppArmor or SELinux).

Privileged mode is independent from running the container as root. This
gives users more control over the security context in proxy-init. The
value may still be used with `runAsRoot: false`.

Fixes #9718

Signed-off-by: Matei David <matei@buoyant.io>
@mateiidavid mateiidavid requested a review from a team as a code owner November 21, 2022 16:59
@@ -41,7 +41,7 @@ imagePullPolicy: {{.Values.proxyInit.image.pullPolicy | default .Values.imagePul
name: linkerd-init
{{ include "partials.resources" .Values.proxyInit.resources }}
securityContext:
{{- if or .Values.proxyInit.closeWaitTimeoutSecs .Values.proxyInit.runAsRoot }}
{{- if or .Values.proxyInit.closeWaitTimeoutSecs .Values.proxyInit.privileged }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious: what is the relationship between .Values.proxyInit.closeWaitTimeoutSecs and this feature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

closeWaitTimeoutSecs is there to address long-running requests (predates me, #4276 should have info about it). The feature can't be used without running in privileged mode, which is why it acts as a conditional in our templates. When the change to run the init container as non-root was made, we've chosen to tackle the issue through templates (linkerd/linkerd2-proxy-init#49 (comment)) and this is since tied to anything that has to do with init container privileges.

Copy link
Member

@alpeb alpeb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic sounds good to me, just some nits 👇

charts/linkerd-control-plane/values.yaml Show resolved Hide resolved
charts/partials/templates/_proxy-init.tpl Outdated Show resolved Hide resolved
@@ -907,6 +909,7 @@ spec:
- mountPath: /var/run/secrets/tokens
name: linkerd-identity-token
initContainers:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea what is causing these empty lines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They don't seem to be introduced by this PR 🤔 I've looked around and I have a bit of an idea about what's going on.

On latest main if I build the CNI and print out the install manifests:

:; git branch -v
  dependabot/cargo/clap-4.0.19               c430080e9 build(deps): bump clap from 4.0.18 to 4.0.19
  eliza/issue-9671                           9b777750b update goldenfiles
* main                                       4ea8ab21d edge-22.11.3 change notes (#9884)
  matei/add-init-priv-escalation             3c0635b7f PR feedback


:; bin/linkerd install  --ignore-cluster| rg 'initContainer' -A 2
      initContainers:

      - args:
--
      initContainers:

      - args:
--
      initContainers:
      - args:
        - --incoming-proxy-port

Culprit seems to be this line:


(and the equivalent line for identity, injector doesn't seem to suffer from this).

To fix, I've added - at the start of the if for destination and identity.

Result:

:; git branch
  dependabot/cargo/clap-4.0.19
  eliza/issue-9671
  main
* matei/add-init-priv-escalation

:; bin/linkerd install  --ignore-cluster| rg 'initContainer' -A 2
      initContainers:
      - args:
        - --incoming-proxy-port
--
      initContainers:
      - args:
        - --incoming-proxy-port
--
      initContainers:
      - args:
        - --incoming-proxy-port

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The templates don't seem to want to update themselves through go test ./... -update though

Copy link
Contributor

@kleimkuhler kleimkuhler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good after Alejandro's comments.

Signed-off-by: Matei David <matei@buoyant.io>
Signed-off-by: Matei David <matei@buoyant.io>
@mateiidavid
Copy link
Member Author

Thanks for the feedback, addressed all of it. Will wait for #9889 (review) to merge first to have the emptyline fix.

Copy link
Member

@alpeb alpeb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mateiidavid , it seems there's still is some funkiness with the empty lines even after having merged #9889, but that's unrelated to this PR.

@mateiidavid mateiidavid merged commit d45f733 into main Nov 25, 2022
@mateiidavid mateiidavid deleted the matei/add-init-priv-escalation branch November 25, 2022 10:58
alpeb pushed a commit that referenced this pull request Dec 8, 2022
This change aims to solve two distinct issues that have cropped up in
the proxy-init configuration.

First, it decouples `allowPrivilegeEscalation` from running proxy-init
as root. At the moment, whenever the container is run as root, privilege
escalation is also allowed. In more restrictive environments, this will
prevent the pod from coming up (e.g security policies may complain about
`allowPrivilegeEscalation=true`). Worth noting that privilege escalation
is not necessary in many scenarios since the capabilities are passed to
the iptables child process at build time.

Second, it introduces a new `privileged` value that will allow users to
run the proxy-init container without any restrictions (meaning all
capabilities are inherited). This is essentially the same as mapping
root on host to root in the container. This value may solve issues in
distributions that run security enhanced linux, since iptables will be
able to load kernel modules that it may otherwise not be able to load
(privileged mode allows the container nearly the same privileges as
processes running outside of a container on a host, this further allows
the container to set configurations in AppArmor or SELinux).

Privileged mode is independent from running the container as root. This
gives users more control over the security context in proxy-init. The
value may still be used with `runAsRoot: false`.

Fixes #9718

Signed-off-by: Matei David <matei@buoyant.io>
sgrzemski pushed a commit to sgrzemski/linkerd2 that referenced this pull request Jan 9, 2023
This change aims to solve two distinct issues that have cropped up in
the proxy-init configuration.

First, it decouples `allowPrivilegeEscalation` from running proxy-init
as root. At the moment, whenever the container is run as root, privilege
escalation is also allowed. In more restrictive environments, this will
prevent the pod from coming up (e.g security policies may complain about
`allowPrivilegeEscalation=true`). Worth noting that privilege escalation
is not necessary in many scenarios since the capabilities are passed to
the iptables child process at build time.

Second, it introduces a new `privileged` value that will allow users to
run the proxy-init container without any restrictions (meaning all
capabilities are inherited). This is essentially the same as mapping
root on host to root in the container. This value may solve issues in
distributions that run security enhanced linux, since iptables will be
able to load kernel modules that it may otherwise not be able to load
(privileged mode allows the container nearly the same privileges as
processes running outside of a container on a host, this further allows
the container to set configurations in AppArmor or SELinux).

Privileged mode is independent from running the container as root. This
gives users more control over the security context in proxy-init. The
value may still be used with `runAsRoot: false`.

Fixes linkerd#9718

Signed-off-by: Matei David <matei@buoyant.io>
Signed-off-by: Szymon Grzemski <sz.grzemski@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Privilege escalation is set to true when proxy-init runs as root iptables Chain already exists
5 participants