-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Reduce the lifetime of exported kubecfg credentials #9593
Conversation
/approve cancel |
Signer: fi.CertificateIDCA, | ||
Type: "client", | ||
Subject: pkix.Name{ | ||
CommonName: "kubecfg", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should use user.Current().Username
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's not a bad change to make at the same time. Or maybe "admin-kubecfg-${USER}", just in case of usage inside a container where I expect most of these will end up as "root" or "jenkins" which might be confusing.
"k8s.io/kops/upup/pkg/fi" | ||
) | ||
|
||
func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, status kops.StatusStore, configAccess clientcmd.ConfigAccess, admin bool, user string) (*KubeconfigBuilder, error) { | ||
const DefaultKubecfgAdminLifetime = 18 * time.Hour |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain the 18 hours default?
It is a pretty big change from previous versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ten years is an unreasonably long time to have an unrevokable credential.
18 hours lets an admin go a working day without having to obtain a new credential, yet makes it likely that their next day starts off with an expired credential. It is more convenient to have to reacquire a credential at the start of a task than mid-way through it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a good explanation for the purpose of strong security.
IMHO, this is a step in the right direction, but may be a bit too extreme. I don't think there was a strong request to reduce the lifetime of the credentials so much. It may be a bit excessive for people with multiple clusters to do this every day, or for every test cluster. I would suggest to change the default to something like 7-30 days that would at least not require new exports for short lived clusters.
Also, an env var may be desirable to change the default to something more suitable for each operator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7-30 days is too long for a default lifetime. Fixed-lifetime credentials that aren't themselves protected by other credentials typically have a lifetime no longer than a day. For example, temporary IAM credentials have a default lifetime of 12 hours.
Do we have a precedent/pattern for env vars providing defaults for flags? The env vars I can think of don't have corresponding flags. Do we want to adopt something like viper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically on the viper point, we do have limited precedent for --state KOPS_STATE_STORE and we even have a config file. However, I couldn't figure out how to get viper to just do this automatically - the state store configuration is a non-trivial amount of repetition. I'm not sure if we're "holding it wrong" but it wasn't very clear.
Multiple clusters (as hakman points out) is indeed going to be more annoying. I'm wondering if we should think about a helper process for login (that's essentially how GKE gets around this problem), or even nudging users to using a different authenticator, reserving the admin kubeconfig for "break glass".
I'm wondering if we could use a helper process to generate this on the fly, effectively chaining off your AWS credentials, so we'd inherit the same validity period.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A kubectl credential plugin is an interesting idea.
For production clusters it would be better to nudge users to use a different authenticator.
@@ -76,7 +77,8 @@ func NewCmdExportKubecfg(f *util.Factory, out io.Writer) *cobra.Command { | |||
|
|||
cmd.Flags().StringVar(&options.KubeConfigPath, "kubeconfig", options.KubeConfigPath, "the location of the kubeconfig file to create.") | |||
cmd.Flags().BoolVar(&options.all, "all", options.all, "export all clusters from the kops state store") | |||
cmd.Flags().BoolVar(&options.admin, "admin", options.admin, "export the cluster admin user and add it to the context") | |||
cmd.Flags().DurationVar(&options.admin, "admin", options.admin, "export a cluster admin user credential with the given lifetime and add it to the cluster context") | |||
cmd.Flags().Lookup("admin").NoOptDefVal = kubeconfig.DefaultKubecfgAdminLifetime.String() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, now that is cool.
@@ -92,7 +94,7 @@ func RunExportKubecfg(ctx context.Context, f *util.Factory, out io.Writer, optio | |||
return fmt.Errorf("cannot use both --all flag and positional arguments") | |||
} | |||
} | |||
if options.admin && options.user != "" { | |||
if options.admin != 0 && options.user != "" { | |||
return fmt.Errorf("cannot use both --admin and --user") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we allow setting the duration when --user
is specified? (--user is not an option I use myself, so I don't really know)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--user
doesn't generate credentials, so a duration isn't relevant.
"k8s.io/kops/upup/pkg/fi" | ||
) | ||
|
||
func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, status kops.StatusStore, configAccess clientcmd.ConfigAccess, admin bool, user string) (*KubeconfigBuilder, error) { | ||
const DefaultKubecfgAdminLifetime = 18 * time.Hour |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically on the viper point, we do have limited precedent for --state KOPS_STATE_STORE and we even have a config file. However, I couldn't figure out how to get viper to just do this automatically - the state store configuration is a non-trivial amount of repetition. I'm not sure if we're "holding it wrong" but it wasn't very clear.
Multiple clusters (as hakman points out) is indeed going to be more annoying. I'm wondering if we should think about a helper process for login (that's essentially how GKE gets around this problem), or even nudging users to using a different authenticator, reserving the admin kubeconfig for "break glass".
I'm wondering if we could use a helper process to generate this on the fly, effectively chaining off your AWS credentials, so we'd inherit the same validity period.
Signer: fi.CertificateIDCA, | ||
Type: "client", | ||
Subject: pkix.Name{ | ||
CommonName: "kubecfg", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's not a bad change to make at the same time. Or maybe "admin-kubecfg-${USER}", just in case of usage inside a container where I expect most of these will end up as "root" or "jenkins" which might be confusing.
func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, status kops.StatusStore, configAccess clientcmd.ConfigAccess, admin bool, user string) (*KubeconfigBuilder, error) { | ||
const DefaultKubecfgAdminLifetime = 18 * time.Hour | ||
|
||
func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, status kops.StatusStore, configAccess clientcmd.ConfigAccess, admin time.Duration, user string) (*KubeconfigBuilder, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I might consider splitting admin into buildAdmin
and duration
; keep this function logical and not too tightly bound to the flags. Although admin=false/0 is weird... it looks like the kubeconfig won't work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A duration
without a buildAdmin
wouldn't make sense. Built credentails with duration
0 would not be useful. buildAdmin
without duration
would be pushing the defaulting logic down, making it less visible to the command line.
Thanks for driving this discussion @johngmyers ... I am going to think more about whether a helper authn process will help us out here, using something like https://kubernetes.io/docs/reference/access-authn-authz/authentication/#input-and-output-formats |
FWIW I think that either way we should merge this PR so that those who provision the static certs really know what they are doing if they are producing long-lived ones. |
@justinsb can we land this now there's a kubectl plugin in the works? |
/lgtm |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: johngmyers The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/approve cancel