-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Append router CA to cluster CA in kubeconfig #1242
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
Append router CA to cluster CA in kubeconfig #1242
Conversation
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.
Can you add some context to the commit message describing the motivation behind this change?
routerSecret, err := client.CoreV1().Secrets("openshift-ingress-operator").Get("router-ca", metav1.GetOptions{}) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
return nil |
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.
Do we really want to silently ignore a missing router-ca
secret?
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.
I will check, but I think there's a possible expectation that it won't be created.
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.
The secret will always be created. However, I'd suggest using the router-ca
configmap in the openshift-config-managed
namespace, which will be created when some clusteringress is using the operator-generated default certificate generated using that CA certificate, and will be absent otherwise.
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.
thanks @Miciah will do!
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.
but also, at the very least log the error. preferably don't swallow it at all.
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.
I've added a log msg for that 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.
Won't we want to poll/wait until the config-map has a non-empty CA instead of giving up?
cmd/openshift-install/create.go
Outdated
return err | ||
} | ||
routerCrtBytes := routerSecret.Data["tls.crt"] | ||
absDir, err := filepath.Abs(directory) |
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.
Why do we need to use the absolute directory?
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.
no we do not, fixed
cmd/openshift-install/create.go
Outdated
return err | ||
} | ||
var kconfig *clientcmdv1.Config | ||
err = yaml.Unmarshal(yml, &kconfig) |
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.
It would be nice to grab the kubeconfig.Admin
asset from the store, which would already have the unmarshaled config. Unfortunately, (1) the asset store used has already gone out of scope, and (2) there is currently no way of fetching from the store without purging the other assets from disk.
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.
right, I pondered that
cmd/openshift-install/create.go
Outdated
} | ||
|
||
clusterCABytes := kconfig.Clusters[0].Cluster.CertificateAuthorityData | ||
appendedCA := string(routerCrtBytes) + string(clusterCABytes) |
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.
"Appended" is not quite the right word here since you are adding the router CA to the beginning not the end.
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.
correct, thanks, i'll rename : )
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.
You can use clientcmd.LoadFromFile and clientcmd.WriteToFile . Might want to use certpool helpers to concat the CAs as well
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.
ah, awesome, thanks
cmd/openshift-install/create.go
Outdated
if apierrors.IsNotFound(err) { | ||
return nil | ||
} | ||
return err |
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.
Wrap the error here and elsewhere in this function.
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.
done
@@ -116,6 +119,10 @@ var ( | |||
logrus.Fatal(err) | |||
} | |||
|
|||
if err = appendRouterCAToClusterCA(config, rootOpts.dir); err != nil { | |||
logrus.Fatal(err) |
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 this be fatal or only a warning? I thinking since it doesn't block accessing the cluster, but maybe it's ok to fail since this is the last step?
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 this be fatal or only a warning?
I'm fine failing fast. We can relax later if necessary, but unless this is fatal by default we don't get CI coverage (or will e2e start failing without this step?).
routerSecret, err := client.CoreV1().Secrets("openshift-ingress-operator").Get("router-ca", metav1.GetOptions{}) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
return nil |
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.
but also, at the very least log the error. preferably don't swallow it at all.
cmd/openshift-install/create.go
Outdated
return err | ||
} | ||
|
||
clusterCABytes := kconfig.Clusters[0].Cluster.CertificateAuthorityData |
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.
check that kconfig != nil
and len(kconfig.Clusters) > 0
before accessing nested fields
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.
done, and outdated here
cmd/openshift-install/create.go
Outdated
} | ||
|
||
clusterCABytes := kconfig.Clusters[0].Cluster.CertificateAuthorityData | ||
appendedCA := string(routerCrtBytes) + string(clusterCABytes) |
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.
You can use clientcmd.LoadFromFile and clientcmd.WriteToFile . Might want to use certpool helpers to concat the CAs as well
83ed4f6
to
2624e1b
Compare
The kubeconfig that you are adding the router ca to has admin credentials, and since you cannot distribute that kubeconfig to a user that is trying to I tried to login following the gist $ unset KUBECONFIG
$ oc login adahiya-1-api.devcluster.openshift.com:6443 --v=6
I0213 14:57:06.751825 7586 round_trippers.go:405] HEAD https://adahiya-1-api.devcluster.openshift.com:6443/ in 273 milliseconds
The server uses a certificate signed by an unknown authority.
You can bypass the certificate check, but any data you send to the server could be intercepted by others.
Use insecure connections? (y/n): y
I0213 14:57:11.749795 7586 round_trippers.go:405] GET https://adahiya-1-api.devcluster.openshift.com:6443/.well-known/oauth-authorization-server 200 OK in 304 milliseconds
I0213 14:57:12.122486 7586 round_trippers.go:405] GET https://openshift-authentication-openshift-authentication.apps.adahiya-1.devcluster.openshift.com/oauth/authorize?client_id=openshift-challenging-client&code_challenge=pQE6QaNhx1d-qtBSA-Wer9BepDDep_Zqn8oT3KnS9mM&code_challenge_method=S256&redirect_uri=https%3A%2F%2Fopenshift-authentication-openshift-authentication.apps.adahiya-1.devcluster.openshift.com%2Foauth%2Ftoken%2Fimplicit&response_type=code 400 Bad Request in 372 milliseconds
I0213 14:57:12.123212 7586 helpers.go:201] server response object: [{
"metadata": {},
"status": "Failure",
"message": "Internal error occurred: unexpected response: 400",
"reason": "InternalError",
"details": {
"causes": [
{
"message": "unexpected response: 400"
}
]
},
"code": 500
}]
F0213 14:57:12.123312 7586 helpers.go:119] Error from server (InternalError): Internal error occurred: unexpected response: 400 It looks like with the current setup
|
2624e1b
to
40311e5
Compare
This PR makes it so that an administrator can test their IDP configuration using the installer generated kubeconfig. For letting other users access the cluster, the admin will need to provide them with the CA bundle.
The |
354a8b6
to
fcef841
Compare
That would work, but would be a major shift from 3.x. People expect to be able to just |
fcef841
to
0afd02b
Compare
/refresh |
/test e2e-aws |
cmd/openshift-install/create.go
Outdated
return errors.New("kubeconfig CertificateAuthorityData not found") | ||
} | ||
certPool := x509.NewCertPool() | ||
if !certPool.AppendCertsFromPEM(clusterCABytes) { |
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.
You're using this just for a parsing check, correct? If so, the error should say something about the CA being not in valid PEM format.
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.
correct, thanks, I've updated the error msg
29cc938
to
5d0e43b
Compare
5d0e43b
to
4033577
Compare
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.
/lgtm
@sallyom can you update the commit message Then we lgtm and merge |
} | ||
|
||
routerCrtBytes := []byte(caConfigMap.Data["ca-bundle.crt"]) | ||
kubeconfig := filepath.Join(directory, "auth", "kubeconfig") |
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.
Ideally we'd hold this in memory, but this is fine short-term.
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.
yes I think there's a FIXME already elsewhere in this file for that
return errors.Wrap(err, "loading kubeconfig") | ||
} | ||
|
||
if kconfig == nil || len(kconfig.Clusters) == 0 { |
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.
I think we want:
if kconfig == nil || len(kconfig.Clusters) != 1 {
return errors.New("invalid kubeconfig")
}
which will also allow us to drop the following loop over Clusters
. We will be able to drop this guard once we switch to keeping the kubeconfig in memory.
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.
I'll open a follow-up? I could not find how to get this string:
// Clusters is a map of referencable names to cluster configs
Clusters map[string]*Cluster
referencable names to cluster configs? What is that reference-able name? I'm happy to do some testing (and open a PR to clarify for others) to figure that out (or maybe someone knows and can tell me). But if there_were_ more than 1 cluster I'd want to add to each, so the != 0 seems ok here. If not I can also include that in the follow-up PR.
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: abhinavdahiya, ericavonb, sallyom 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 |
Hmm. Does this mean "we never rotate the router CA"? Because if we did, it would break |
@wking yes, correct, a change in router-CA will break |
Yes, and this is expected. This change is only expected to handle the OOTB experience. |
This was added in 4033577 (Append router CA to cluster CA in kubeconfig, 2019-02-12, openshift#1242), where the motivation was [1]: With users created with an identity-provider, OAuth flow goes through router and router-ca is not trusted. This prohibits the user from using oc login from command line, without manually appending the router ca to the cluster ca. The openshift-ingress-operator creates the router-CA and this is not available until the very end of an install. This PR adds the router CA from configmap router-ca -n openshift-config-managed to the kubeconfig certificate-authority-data. This allows an identity-provided user to oc login from the terminal. But the admin kubeconfig is already authenticated, so folks shouldn't be using 'oc login' with that kubeconfig. For example, see dee6929 (Modify kubeadmin usage message, admins should not use kubeadmin via CLI, 2019-04-01, openshift#1513). That leaves us with no use case for this modification, and making the finish code watch-only sets us up to rename away from the user-provided-infrastructure subcommand. [1]: openshift#1242 (comment)
The console may become optional [1], so teach the installer to handle its absence gracefully. We've waited on the console since way back in ff53523 (add logs at end of install for kubeadmin, consoleURL, 2018-12-06, openshift#806). Back then, install-complete timing was much less organized, and since e17ba3c (cmd: wait for the cluster to be initialized, 2019-01-25, openshift#1132) we've blocked on ClusterVersion going Available=True. So the current dependency chain is: 1. Console route admission blocks console operator from going Available=True in its ClusterOperator. 2. Console ClusterOperator blocks cluster-version operator from going Available=True in ClusterVersion. 3. ClusterVersion blocks installer's waitForInitializedCluster. So we no longer need to wait for the route to show up, and can fail fast if we get a clear IsNotFound. I'm keeping a bit of polling so we don't fail an install on a temporary network hiccup. We don't want to drop the console check entirely, because when it is found, we want: * To continue to log that access pathway on install-complete. * To continue to append the router CA to the kubeconfig. That latter point has been done since 4033577 (append router CA to cluster CA in kubeconfig, 2019-02-12, openshift#1242). The motivation in that commit message is not explicit, but the idea is to support folks who naively run 'oc login' with the kubeadmin kubeconfig [2] (despite that kubeconfig already having cluster-root access) when the console route's cert's CA happens to be something that the user's local trust store doesn't include by default. [1]: openshift/enhancements#922 [2]: openshift#1541 (comment)
With users created with an identity-provider, OAuth flow goes through router and router-ca is not trusted. This prohibits the user from using
oc login
from command line, without manually appending the router ca to the cluster ca. The openshift-ingress-operator creates the router-CA and this is not available until the very end of an install.This PR adds the router CA from
configmap router-ca -n openshift-config-managed
to the kubeconfig certificate-authority-data. This allows an identity-provided user tooc login
from the terminal.