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

use rootless containers where possible #493

Merged
merged 5 commits into from
Apr 21, 2021
Merged

Conversation

kschoche
Copy link
Contributor

@kschoche kschoche commented Apr 20, 2021

Changes proposed in this PR:

How I've tested this PR:
unit tests.
I've deployed this into a test cluster with a sample app that has:
(1) no pod security contexts
and
(2) pod security context :

  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
    runAsNonRoot: true

and confirmed that the pod deploys succesfully with the changes to the init container and fails without them.

How I expect reviewers to test this PR:
unit tests / run it.

Checklist:

  • Tests added
  • CHANGELOG entry added (HashiCorp engineers only, community PRs should not add a changelog entry)

@kschoche kschoche added the theme/tproxy Items related to transparent proxy label Apr 20, 2021
@kschoche kschoche requested a review from a team April 20, 2021 20:39
@kschoche kschoche self-assigned this Apr 20, 2021
@kschoche kschoche requested review from lkysow and ishustava and removed request for a team April 20, 2021 20:39
@thisisnotashwin thisisnotashwin changed the base branch from master to adding-to-ep-controller April 20, 2021 20:48
@thisisnotashwin thisisnotashwin changed the base branch from adding-to-ep-controller to master April 20, 2021 20:49
@kschoche kschoche closed this Apr 20, 2021
@kschoche kschoche reopened this Apr 20, 2021
Copy link
Contributor

@ishustava ishustava left a comment

Choose a reason for hiding this comment

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

Looks great!! The only thing that's blocking I think is failing when security context of the application container (not only pod) uses the same uid as Envoy. Everything else looks great!

CHANGELOG.md Outdated
Comment on lines 3 to 5
FEATURES:
* Connect: Add a security context to the init copy container and the envoy sidecar and ensure they do not run as root. Also use `RunAsNonRoot: false` for connect-init's container when tproxy is enabled. [[GH-493](https://github.com/hashicorp/consul-k8s/pull/493)]

Copy link
Contributor

Choose a reason for hiding this comment

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

Also use RunAsNonRoot: false for connect-init's container when tproxy is enabled.

should this be recorded as a bug?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure! good idea!

connect-inject/container_init.go Show resolved Hide resolved
connect-inject/container_init.go Outdated Show resolved Hide resolved
connect-inject/container_init.go Outdated Show resolved Hide resolved
connect-inject/envoy_sidecar.go Show resolved Hide resolved
connect-inject/envoy_sidecar.go Show resolved Hide resolved
@@ -205,8 +204,8 @@ func (h *Handler) Handle(_ context.Context, req admission.Request) admission.Res
}
pod.Spec.InitContainers = append(pod.Spec.InitContainers, initContainer)

// Add the Envoy and Consul sidecars.
envoySidecar, err := h.envoySidecar(pod, req.Namespace)
// Add the Envoy sidecar.
Copy link
Contributor

Choose a reason for hiding this comment

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

🙏

@kschoche kschoche requested a review from ishustava April 20, 2021 22:52
Copy link
Member

@lkysow lkysow 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. Mainly wondering about the uid for the copy container.

CHANGELOG.md Outdated
* Connect: Add a security context to the init copy container and the envoy sidecar and ensure they do not run as root. [[GH-493](https://github.com/hashicorp/consul-k8s/pull/493)]

BUG FIXES:
* Connect: Use `RunAsNonRoot: false` for connect-init's container when tproxy is enabled. [[GH-493](https://github.com/hashicorp/consul-k8s/pull/493)]
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* Connect: Use `RunAsNonRoot: false` for connect-init's container when tproxy is enabled. [[GH-493](https://github.com/hashicorp/consul-k8s/pull/493)]
* Connect: Use `runAsNonRoot: false` for connect-init's container when tproxy is enabled. [[GH-493](https://github.com/hashicorp/consul-k8s/pull/493)]

@@ -37,6 +38,8 @@ type initContainerCommandData struct {
PrometheusScrapePath string
// PrometheusBackendPort configures where the listener on Envoy will point to.
PrometheusBackendPort string
// EnvoyUID is the UID that `consul connect redirect-traffic` will use when tproxy is enabled.
Copy link
Member

Choose a reason for hiding this comment

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

I found this comment confusing because it says it's envoy's UID but then it says it's for the command consul connect redirect-traffic.

Upon further reading I see that this is what gets passed into that command's -proxy-uid flag so that makes sense now but I'm thinking this comment should either just say "this is envoy's linux user id" without talking about the redirect-traffic command or it should say "this is envoy's linux user id that will be passed to the -proxy-uid flag of consul connect redirect-traffic".

@@ -37,6 +38,8 @@ type initContainerCommandData struct {
PrometheusScrapePath string
// PrometheusBackendPort configures where the listener on Envoy will point to.
PrometheusBackendPort string
// EnvoyUID is the UID that `consul connect redirect-traffic` will use when tproxy is enabled.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// EnvoyUID is the UID that `consul connect redirect-traffic` will use when tproxy is enabled.
// EnvoyUID is the Linux user ID that `consul connect redirect-traffic` will use when tproxy is enabled.

For folks that don't know what UID stands for.

Comment on lines 67 to 68
RunAsUser: pointerToInt64(envoyUserAndGroupID),
RunAsGroup: pointerToInt64(envoyUserAndGroupID),
Copy link
Member

Choose a reason for hiding this comment

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

why does the copy container need to run as the envoy user?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Without setting a UID it will run as root because that is the default of the consul container.

Copy link
Member

Choose a reason for hiding this comment

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

Ahh interesting. So we can pick any random uid here as long at it's not 0 and we're good?

Can you add a comment explaining that here 🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, exactly! And I just picked the same UID as envoy so I didn't have to make another constant. I'll definitely add a comment to clarify thanks for pointing this out!!

$ kubectl exec -it counting -c envoy-sidecar -- sh
/ $ ls -lah /consul/connect-inject/consul
-rwxr-xr-x    1 5995     5995      111.7M Apr 20 20:44 /consul/connect-inject/consul

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe to avoid confusion, we should use a different user? In the RFC, we proposed 5996.

@@ -78,6 +87,7 @@ func (h *Handler) containerInit(pod corev1.Pod, k8sNamespace string) (corev1.Con
NamespaceMirroringEnabled: h.EnableK8SNSMirroring,
ConsulCACert: h.ConsulCACert,
EnableTransparentProxy: tproxyEnabled,
EnvoyUID: strconv.Itoa(envoyUserAndGroupID),
Copy link
Member

Choose a reason for hiding this comment

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

I think we can pass it in as an int since the template will render it corrctly.

if tt.CmdNot != "" {
require.NotContains(actual, tt.CmdNot)
require.NotContains(tt.CmdNot, actual)
Copy link
Member

Choose a reason for hiding this comment

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

Looks like none of the test cases set CmdNot so you can remove this field altogether.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nice catch!

@@ -467,9 +468,9 @@ consul-k8s connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \
container, err := h.containerInit(*tt.Pod(minimal()), k8sNamespace)
require.NoError(err)
actual := strings.Join(container.Command, " ")
require.Equal(actual, tt.Cmd)
require.Equal(tt.Cmd, actual)
Copy link
Member

Choose a reason for hiding this comment

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

🍺

for _, c := range pod.Spec.Containers {
// User container and Envoy container cannot have the same UID.
if c.SecurityContext != nil && c.SecurityContext.RunAsUser != nil && *c.SecurityContext.RunAsUser == envoyUserAndGroupID {
return corev1.Container{}, fmt.Errorf("user containers cannot have the same uid as envoy: %v", envoyUserAndGroupID)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return corev1.Container{}, fmt.Errorf("user containers cannot have the same uid as envoy: %v", envoyUserAndGroupID)
return corev1.Container{}, fmt.Errorf("container %q has runAsUser set to the same uid %q as envoy which is not allowed", c.Name, envoyUserAndGroupID)

This error will be shown during kubectl describe so I think it should make sense in that context and be as helpful as possible. A user won't think of their containers as "user containers", they'll just think of them as their pod's containers. Nice to include the specific container's name too. This is just a suggestion for a possible error that meets that criteria.

_, err := h.envoySidecar(pod)
require.Error(err, fmt.Sprintf("user containers cannot have the same uid as envoy: %v", envoyUserAndGroupID))
}

Copy link
Member

Choose a reason for hiding this comment

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

👍 good test coverage.


BUG FIXES:
* Connect: Use `RunAsNonRoot: false` for connect-init's container when tproxy is enabled. [[GH-493](https://github.com/hashicorp/consul-k8s/pull/493)]

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should also call out that we will error out if you have the same user as envoy as a breaking change. Unless we want to error out only when tproxy is enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah good point. But now I have a FEATURE + BREAKING CHANGE + BUG FIX entry in the changelog against the same PR, can we consolidate this somehow?

Copy link
Contributor

Choose a reason for hiding this comment

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

Haha, yes that's true. Maybe change the non-bug fix to a breaking change and add a note about what's breaking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ishustava how does this look?

Copy link
Contributor

Choose a reason for hiding this comment

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

Perfect!

Comment on lines 67 to 68
RunAsUser: pointerToInt64(envoyUserAndGroupID),
RunAsGroup: pointerToInt64(envoyUserAndGroupID),
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe to avoid confusion, we should use a different user? In the RFC, we proposed 5996.

@@ -248,7 +249,6 @@ func TestHandlerContainerInit_namespacesEnabled(t *testing.T) {
Pod func(*corev1.Pod) *corev1.Pod
Handler Handler
Cmd string // Strings.Contains test
CmdNot string // Not contains
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unused in this test.

@kschoche kschoche requested a review from lkysow April 21, 2021 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme/tproxy Items related to transparent proxy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants