Skip to content
This repository has been archived by the owner on Jul 30, 2021. It is now read-only.

pkg/asset: use service accounts for checkpointer and kube-proxy creds #767

Merged
merged 1 commit into from
Nov 15, 2017
Merged

pkg/asset: use service accounts for checkpointer and kube-proxy creds #767

merged 1 commit into from
Nov 15, 2017

Conversation

ericchiang
Copy link
Contributor

@ericchiang ericchiang commented Nov 9, 2017

Today, both the checkpointer and kube-proxy re-use the kubelet's credentials to talk to the API server. This means we can't target them with specific RBAC profiles or identify them in audit logs. In addition, when we move to TLS bootstrapping (#663), the kubelet's kubeconfig will no longer hold real credentials.

Switch the checkpointer and kube-proxy to use service account credentials instead of the kubelet's kubeconfig.

Extracted from #663 to make that PR smaller.

cc @dghubble @rphillips

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Nov 9, 2017
@aaronlevy
Copy link
Contributor

Can you add a description of why this is needed?

@ericchiang
Copy link
Contributor Author

@aaronlevy added a description.

@dghubble
Copy link
Contributor

dghubble commented Nov 9, 2017

We don't have any hard rules around this, but I'd aim to put this in a v0.9.0 followup to v0.8.2 since there is a new render asset.

@dghubble
Copy link
Contributor

dghubble commented Nov 9, 2017

Can we have kube-proxy and checkpointer each use their own named service account instead of a service-account-kubeconfig.yaml?

@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Nov 10, 2017
@ericchiang
Copy link
Contributor Author

@dghubble updated with RBAC roles.

`)

var CheckpointerRole = []byte(`apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
Copy link
Contributor Author

@ericchiang ericchiang Nov 10, 2017

Choose a reason for hiding this comment

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

Note: if the pod-checkpointer only watches kube-system (e.g. its own namespace) we can drop this to a Role. It doesn't currently.

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 this is ok to keep for now but add to the checkpointer README and the release note.

Copy link
Contributor

@dghubble dghubble left a comment

Choose a reason for hiding this comment

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

Mainly just questions


// ServiceAccountKubeConfig is used for pods that don't have access to the
// KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT environment variables.
// This is used for kube-proxy, since it configures these endpoints itself,
Copy link
Contributor

Choose a reason for hiding this comment

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

Its also being used for the pod-checkpointer here. Whats the reason there?

namespace: kube-system
`)

// ServiceAccountKubeConfig is used for pods that don't have access to the
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you clarify "used for"? This still feels odd and kinda opaque. So before we relied on the host's kubeconfig which contained both endpoint info and credentials. With the service account approach you use an alternate kubeconfig which specifies the endpoint info and the local service account in the pod.

What's the tie in to these environment variables?

KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.3.0.1:443

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Clients compiled with client-go require the KUBERNETES_SERVICE_PORT and KUBERNETES_PORT to use the in-cluster config.

https://github.com/kubernetes/client-go/blob/kubernetes-1.8.2/rest/config.go#L318-L321

These aren't exposed to kube-proxy (since kube proxy sets up the endpoint) or the checkpointer, since it runs as a static pod.

This work:

// ServiceAccountKubeConfig instructs clients to use their service account token, but unlike an in-cluster client
// doesn't rely on the `KUBERNETES_SERVICE_PORT` and `KUBERNETES_PORT` to determine the API
// servers address. This kubeconfig is used bootstrapping pods that might not have access to these env vars,
// such as kube-proxy, which sets up the endpoint (chicken and egg), and the checkpointer, which needs to run
// as a static pod even if the API server isn't available.

@@ -37,6 +37,9 @@ const (
AssetPathManifests = "manifests"
AssetPathKubelet = "manifests/kubelet.yaml"
AssetPathProxy = "manifests/kube-proxy.yaml"
AssetPathProxySA = "manifests/kube-proxy-sa.yaml"
AssetPathProxyRoleBinding = "manifests/kube-proxy-role-binding.yaml"
AssetPathServiceAccountKubeConfig = "manifests/service-account-kubeconfig.yaml"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: everywhere else, we say the name followed by the type. KubeconfigServiceAccount and kubeconfig-sa.yaml?

Copy link
Contributor

Choose a reason for hiding this comment

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

See below, got confused. Its not a service account.

var ServiceAccountKubeConfigTemplate = []byte(`apiVersion: v1
kind: Secret
metadata:
name: service-account-kubeconfig
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: kubeconfig-service-account or just kubeconfig

metadata:
name: service-account-kubeconfig
namespace: kube-system
stringData:
Copy link
Contributor

Choose a reason for hiding this comment

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

Cool, I missed this getting into upstream.

- name: etc-kubernetes
hostPath:
path: /etc/kubernetes
name: ssl-certs-host
Copy link
Contributor

Choose a reason for hiding this comment

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

accidental duplicate from a few lines above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, thanks for catching.

@ericchiang
Copy link
Contributor Author

@dghubble thanks for the review. Comments addressed.

@@ -37,6 +37,9 @@ const (
AssetPathManifests = "manifests"
AssetPathKubelet = "manifests/kubelet.yaml"
AssetPathProxy = "manifests/kube-proxy.yaml"
AssetPathProxySA = "manifests/kube-proxy-sa.yaml"
AssetPathProxyRoleBinding = "manifests/kube-proxy-role-binding.yaml"
AssetPathServiceAccountKubeConfig = "manifests/kubeconfig-sa.yaml"
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, my nit doesn't help much. Its still confusing to read since this is actually a secret. eh, better idea?

Copy link
Contributor

Choose a reason for hiding this comment

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

in-cluster-kubeconfig? which happens to be a secret or configmap?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does manifest/kubeconfig-in-cluster.yaml work?

Copy link
Contributor

Choose a reason for hiding this comment

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

sgtm

@ericchiang
Copy link
Contributor Author

e2e passed but it looks like there's something wrong with the Jenkins GitHub plugin https://gist.github.com/ericchiang/1b80ef7c23ed4adf27527e728e04e2d3

@dghubble
Copy link
Contributor

Also, FAIL: TestCheckpointerUnscheduleCheckpointer. Can you re-run? Possibly with the renamed in-cluster-kubeconfig

@ericchiang
Copy link
Contributor Author

/assign @diegs

For final merge.

Copy link
Contributor

@diegs diegs left a comment

Choose a reason for hiding this comment

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

LGTM

Nice work! Just a few small comments but I'm good to merge.

`)

var CheckpointerRole = []byte(`apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
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 this is ok to keep for now but add to the checkpointer README and the release note.

pkg/asset/k8s.go Outdated
@@ -40,6 +41,9 @@ func newStaticAssets(imageVersions ImageVersions) Assets {
MustCreateAssetFromTemplate(AssetPathControllerManagerDisruption, internal.ControllerManagerDisruptionTemplate, conf),
MustCreateAssetFromTemplate(AssetPathKubeDNSDeployment, internal.DNSDeploymentTemplate, conf),
MustCreateAssetFromTemplate(AssetPathCheckpointer, internal.CheckpointerTemplate, conf),
Asset{AssetPathCheckpointerSA, internal.CheckpointerServiceAccount},
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 it might be more uniform (and less surprising in the future) to pass these through MustCreateAssetFromTemplate even if they currently do not do any templating.

@ericchiang
Copy link
Contributor Author

coreosbot run e2e

@ericchiang
Copy link
Contributor Author

Last couple nits addressed.

Copy link
Contributor

@diegs diegs left a comment

Choose a reason for hiding this comment

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

Awesome!

`)

// TODO: Drop checkpointer RBAC resources to a Role and RoleBinding if
// the checkpoint switches to only watching kube-system.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just make this change? It only needs to watch kube-system (also can be follow-up PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can open a separate PR. We'd have to wait the checkpointer change to merged before we drop this to a role, so we can't do it in one PR anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why would the checkpointer have to be changed? It just wouldn't have access to non-kube-system right?

Copy link
Contributor Author

@ericchiang ericchiang Nov 15, 2017

Choose a reason for hiding this comment

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

Checkpointer attempts to watch all namespaces. If we restrict it now that request will fail. We have to submit a change to the checkpointer.

https://github.com/kubernetes-incubator/bootkube/blob/v0.8.2/pkg/checkpoint/apiserver.go#L18

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Opened the checkpointer PR #774

@dghubble dghubble merged commit e851d3e into kubernetes-retired:master Nov 15, 2017
@ericchiang ericchiang deleted the authn-checkpointer-kube-proxy-sa branch November 15, 2017 23:41
dghubble added a commit to poseidon/terraform-render-bootstrap that referenced this pull request Nov 17, 2017
* Create separate service accounts for kube-proxy and pod-checkpointer
* Switch kube-proxy and pod-checkpointer to use a kubeconfig that
references the local service account, rather than the host kubeconfig
* kubernetes-retired/bootkube#767
// (chicken and egg), and the checkpointer, which needs to run as a static pod
// even if the API server isn't available.
var KubeConfigInClusterTemplate = []byte(`apiVersion: v1
kind: Secret
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it need to be a secret? There is no sensitive data in this resource, would you consider merging PR which changes it to ConfigMap?

- name: local
cluster:
server: {{ .Server }}
certificate-authority-data: {{ .CACert }}
Copy link
Contributor

Choose a reason for hiding this comment

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

Another options is to use certificate-authority: /run/secrets/kubernetes.io/serviceaccount/ca.crt which makes it somewhat easier to rotate keys in the future (assuming that resources installed by bootkube are forming a basis for core cluster resources, which are then managed separately)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants