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

BootstrapSigner and TokenCleaner controllers #36101

Merged
merged 5 commits into from Feb 10, 2017

Conversation

jbeda
Copy link
Contributor

@jbeda jbeda commented Nov 2, 2016

This is part of kubernetes/enhancements#130 and is an implementation of kubernetes/community#189.

Work that needs to be done yet in this PR:

  • e2e tests Will come in new PR.
  • flag to disable this by default
Native support for token based bootstrap flow.  This includes signing a well known ConfigMap in the `kube-public` namespace and cleaning out expired tokens.

@kubernetes/sig-cluster-lifecycle @dgoodwin @roberthbailey @mikedanese


This change is Reviewable

@jbeda jbeda added area/controller-manager sig/cluster-lifecycle Categorizes an issue or PR as relevant to SIG Cluster Lifecycle. release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Nov 2, 2016
@k8s-github-robot k8s-github-robot added kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Nov 2, 2016
Copy link
Contributor

@dgoodwin dgoodwin left a comment

Choose a reason for hiding this comment

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

Just adding some thoughts from an early pass through.

Is it possible to play with this right now? I've made two attempts to get this deployed and running (built my own hyperkube image and deployed it with kubeadm, and the new dind stuff that hit our ML this morning), in both cases I can't seem to trigger anything happening. I've created bootstrap tokens per my WIP PR but no config maps show up in kube-public.

maxRetries := options.MaxRetries
if maxRetries == 0 {
maxRetries = 10
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Would DefaultBootstrapSignerOptions be a better place to define that default?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the pattern that other modules follow. Folks don't have to use DefaultBootstrapSignerOptions so this deals with that case.

}
configMapSelector := fields.SelectorFromSet(map[string]string{api.ObjectNameField: options.ConfigMapName})
e.configMaps, e.configMapsController = cache.NewInformer(
&cache.ListWatch{
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we monitor the config map itself? I would have expected monitoring secrets and then eventually API servers, and assumed that when a change was detected the config map is considered "ours" to be completely re-synced.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is no way to monitor "API servers". At some point we may have a way to update this directly but we aren' there yet. To start with this config map will be written as part of set up and rarely changed. As we move to HA we can update it as the HA set changes and this controller will automatically react and sign.

if _, ok := ret[tokenID]; ok {
glog.V(3).Infof("Duplicate bootstrap tokens found for id %s, ignoring on in %s/%s", tokenID, secret.Namespace, secret.Name)
continue
}
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 creating these as prefix-tokenID so hopefully it won't be possible for a duplicate ID to appear 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.

The name doesn't matter here as we are keying off of the secret type.

MaxRetries int
}

// DefaultBootstrapSignerOptions returns a set of default options for creating a
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a missed ref to wrong struct name in comment 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.

Fixed

// signConfigMap computes the signatures on our latest cached objects and writes
// back if necessary.
func (e *BootstrapSigner) signConfigMap() {
configMaps := e.listConfigMaps()
Copy link
Contributor

Choose a reason for hiding this comment

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

Trying to get this to run so I could poke around but not having much luck yet, I am curious why multiple config maps are referenced here? (would have expected just the one)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed to just grab the one. Was easy enough either way.

ret := &api.Secret{
ObjectMeta: api.ObjectMeta{
Namespace: api.NamespaceSystem,
Name: "token-" + tokenID,
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure it matters but these are "bootstrap-token-" on my end, if so which should we sync on?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again, we key off of the secret type so this doesn't matter.

core.NewUpdateAction(unversioned.GroupVersionResource{Resource: "configmaps"},
api.NamespacePublic,
newConfigMap("tokenID", "eyJhbGciOiJIUzI1NiIsImtpZCI6InRva2VuSUQifQ..QAvK9DAjF0hSyASEkH1MOTB5rJMmbWEY9j-z1NSYILE")),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This testing stuff looks interesting, I need to see if I can make use of this for unit testing the kubeadm token commands.

@mikedanese mikedanese assigned mikedanese and unassigned bprashanth Nov 4, 2016
bootstrap.NewBootstrapSigner(
client("bootstrap-signer"),
bootstrap.DefaultBootstrapSignerOptions(),
).Run()
Copy link
Member

Choose a reason for hiding this comment

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

Run should be started with the stop chan that is in scope here like other controllers. It should not have an explicit stop method, but should stop when the channel is closed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool -- the pattern changed from when I first wrote this. Also note that stopping controllers is currently pretty busted. It would be better to use ctx. But that is too big a change. See: https://github.com/kubernetes/kubernetes/blob/master/pkg/client/cache/controller.go#L125

}

// listConfigMaps lists all of the cached config maps
func (e *BootstrapSigner) listConfigMaps() []*api.ConfigMap {
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, Listers take an indexer. I don't have one of those as I don't need to watch across namespaces. It seems silly to create an indexer just to avoid writing a 7 line function.

return items
}

func (e *BootstrapSigner) listSecrets() []*api.Secret {
Copy link
Member

Choose a reason for hiding this comment

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

same as above, use a lister

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same -- not indexing this so I can't easily use a lister.

options.SecretResync,
cache.ResourceEventHandlerFuncs{
AddFunc: func(_ interface{}) { e.signConfigMap() },
UpdateFunc: func(_, _ interface{}) { e.signConfigMap() },
Copy link
Member

@mikedanese mikedanese Nov 4, 2016

Choose a reason for hiding this comment

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

why not accept a config map from signConfigMap() ? Then you only check configmaps that changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This simplifies the flow. We want to resign whenever we get a new/changed/deleted token or if the config map changes. In the token change case we don't have the config map already. This way everything just funnels down to a single "reconcile the world" function.

If we were signing a lot of config maps it would make sense to be more surgical.

@luxas luxas added this to the v1.6 milestone Nov 12, 2016
@luxas
Copy link
Member

luxas commented Nov 17, 2016

@jbeda Are you planning to get back to this soon so we can have it lgtm'd when master is opening for merges again?
This will be one of the most critical pieces for us to get in in time for v1.6, so the sooner we have something like this the better

@jbeda
Copy link
Contributor Author

jbeda commented Nov 21, 2016

@luxas -- yeah. I'll be getting back to this soon. Just coming up from air from the Heptio launch now.

@luxas
Copy link
Member

luxas commented Nov 22, 2016

Yeah, really cool. Understand that totally, guess it has been a hectic week.
Now it seems like you've figured out what to do :)

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 8, 2016
@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Dec 13, 2016
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 13, 2016
@jbeda jbeda force-pushed the bootstrap-signer branch 3 times, most recently from ac1bba7 to 7235e14 Compare December 13, 2016 22:22
@jbeda jbeda added the do-not-merge DEPRECATED. Indicates that a PR should not merge. Label can only be manually applied/removed. label Dec 13, 2016
@jbeda jbeda force-pushed the bootstrap-signer branch 2 times, most recently from 18cb472 to 6ac4bc8 Compare December 14, 2016 00:15
@jbeda
Copy link
Contributor Author

jbeda commented Feb 10, 2017

@deads2k @mikedanese PTAL

Talked to @smarterclayton quickly and I think I got to the root of what he was looking for.

@luxas luxas removed the do-not-merge DEPRECATED. Indicates that a PR should not merge. Label can only be manually applied/removed. label Feb 10, 2017
@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 10, 2017
@ericchiang
Copy link
Contributor

Per conversation in the sig-auth channel with @luxas and @liggitt, there we issues with using token.csv.

@liggitt suggested we add a "BootstrapTokenAuthenticator" to handle these cases. That authenticator would look for secrets of type bootstrap.kubernetes.io/token:

apiVersion: v1
kind: Secret
metadata:
  name: simple-bootstrapper
  namespace: kube-system # Only watch tokens in the "kube-system" namespace?
data:
  token-secret: ( bearer token )
  token-id: ( token id )
type: bootstrap.kubernetes.io/token

A request that authenticates using the "( bearer token )" would get the username system:bootstrap:( token id ) and the group system:bootstrappers.

In the short term admins will have to manually create a cluster role binding the group or name to the existing system:node-bootstrapper[0].

cc @liggitt @luxas @jbeda does that accurately summarize the conversation? I'm happy to go add this if it does.

[0]

- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
creationTimestamp: null
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:node-bootstrapper
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- get
- list
- watch

@liggitt
Copy link
Member

liggitt commented Feb 10, 2017

cc @liggitt @luxas @jbeda does that accurately summarize the conversation? I'm happy to go add this if it does.

that sounds about right to me. the authenticator bits are distinct from this PR or from any bootstrap bindings if you want to get started in parallel

@jbeda
Copy link
Contributor Author

jbeda commented Feb 10, 2017

@ericchiang Yes -- that is the idea. That would be another PR, obviously. I'd propose we document this as part of https://github.com/kubernetes/community/blob/master/contributors/design-proposals/bootstrap-discovery.md (or perhaps a companion proposal)

This adds these to the list of controllers the Controller Manager can start.  But as these are alpha, they are also currently disabled by default.
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 10, 2017
@luxas
Copy link
Member

luxas commented Feb 10, 2017

cc @liggitt @luxas @jbeda does that accurately summarize the conversation? I'm happy to go add this if it does.

👍

@mikedanese
Copy link
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 10, 2017
@k8s-github-robot
Copy link

Automatic merge from submit-queue (batch tested with PRs 38252, 41122, 36101, 41017, 41264)

@k8s-github-robot k8s-github-robot merged commit 866aa73 into kubernetes:master Feb 10, 2017
k8s-github-robot pushed a commit that referenced this pull request Feb 15, 2017
Automatic merge from submit-queue (batch tested with PRs 41378, 41413, 40743, 41155, 41385)

Expose the constants in pkg/controller/bootstrap and add a validate token function

**What this PR does / why we need it**: In order to hook up #36101 against kubeadm, we have to expose the constants and add a function to validate the token

**Special notes for your reviewer**:

**Release note**:

```release-note
NONE
```
cc @jbeda @mikedanese @pires @dmmcquay
k8s-github-robot pushed a commit that referenced this pull request Feb 23, 2017
Automatic merge from submit-queue (batch tested with PRs 41812, 41665, 40007, 41281, 41771)

kube-apiserver: add a bootstrap token authenticator for TLS bootstrapping

Follows up on #36101

Still needs:

* More tests.
* To be hooked up to the API server.
  - Do I have to do that in a separate PR after k8s.io/apiserver is synced?
* Docs (kubernetes.io PR).
* Figure out caching strategy.
* Release notes.

cc @kubernetes/sig-auth-api-reviews @liggitt @luxas @jbeda

```release-notes
Added a new secret type "bootstrap.kubernetes.io/token" for dynamically creating TLS bootstrapping bearer tokens.
```
k8s-github-robot pushed a commit that referenced this pull request Mar 4, 2017
Automatic merge from submit-queue

Remove the kube-discovery binary from the tree

**What this PR does / why we need it**:

kube-discovery was a temporary solution to implementing proposal: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/bootstrap-discovery.md

However, this functionality is now gonna be implemented in the core for v1.6 and will fully replace kube-discovery:
 - #36101 
 - #41281
 - #41417

So due to that `kube-discovery` isn't used in any v1.6 code, it should be removed.
The image `gcr.io/google_containers/kube-discovery-${ARCH}:1.0` should and will continue to exist so kubeadm <= v1.5 continues to work.

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #

**Special notes for your reviewer**:

**Release note**:

```release-note
Remove cmd/kube-discovery from the tree since it's not necessary anymore
```
@jbeda @dgoodwin @mikedanese @dmmcquay @lukemarsden @errordeveloper @pires
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/controller-manager cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/cluster-lifecycle Categorizes an issue or PR as relevant to SIG Cluster Lifecycle. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet