From a2065310e9c72498ee4eee10d44223dc0d00d437 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 15 Oct 2018 23:34:06 -0700 Subject: [PATCH] WIP: Add certificate-authority injection This allows you to connect your cluster to external services whose X.509 certificates are signed by a certificate authority that doesn't belong to the OSes list of certificate authorities. For example, it allows you to use a local registry with a self-signed certificate. While this might seem like a use-case for a custom root CA: * We don't currently install the root CA for general use on the bootstrap node, so the bootstrap node would still have trouble pulling images from a local registry with a nonstandard CA. * The root CA for the cluster and the CA for a local registry are really completely independent. I don't want to make a caller have to provide a complete set of custom certs and keys for all of our cluster-specific roles if all they need to do is authenticate a local registry. The commit is a work in progress, because: * This may be something of a niche use-case, I don't really know. If it is, it may not belong in the install-config. I guess users could edit generated ignition files and inject these directly once #374 lands. Or they could edit the generated install config to inject these there. However this shakes out, the environment variable I'm using here is almost certainly not going to be the final UI. * I'm currently ignoring `installConfig.Machines[*].CertificateAuthorities` while I play around with mirroring [1]. If it works out, I'll go over this again and clean up the `pointerIgnitionConfig` API to allow for selecting the appropriate `installConfig.Machines` entry. [1]: https://github.com/wking/openshift-installer/blob/mirror-docs/docs/user/local-mirror.md --- pkg/asset/ignition/bootstrap/bootstrap.go | 16 ++++++++++++++++ pkg/asset/ignition/machine/node.go | 18 +++++++++++++++--- pkg/asset/installconfig/installconfig.go | 6 ++++++ pkg/types/installconfig.go | 6 ++++++ pkg/types/machinepools.go | 5 +++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/pkg/asset/ignition/bootstrap/bootstrap.go b/pkg/asset/ignition/bootstrap/bootstrap.go index 61cc881be1c..9314cc2b7f9 100644 --- a/pkg/asset/ignition/bootstrap/bootstrap.go +++ b/pkg/asset/ignition/bootstrap/bootstrap.go @@ -12,6 +12,7 @@ import ( igntypes "github.com/coreos/ignition/config/v2_2/types" "github.com/pkg/errors" log "github.com/sirupsen/logrus" + "github.com/vincent-petithory/dataurl" "github.com/openshift/installer/pkg/asset" "github.com/openshift/installer/pkg/asset/ignition" @@ -113,6 +114,21 @@ func (a *Bootstrap) Generate(dependencies asset.Parents) error { igntypes.PasswdUser{Name: "core", SSHAuthorizedKeys: []igntypes.SSHAuthorizedKey{igntypes.SSHAuthorizedKey(installConfig.Config.Admin.SSHKey)}}, ) + authorities := installConfig.Config.DefaultCertificateAuthorities + if len(authorities) > 0 { + certificateAuthorities := make([]igntypes.CaReference, 0, len(authorities)) + for _, certificateAuthority := range authorities { + certificateAuthorities = append(certificateAuthorities, igntypes.CaReference{ + Source: dataurl.EncodeBytes([]byte(certificateAuthority)), + }) + } + a.Config.Ignition.Security = igntypes.Security{ + TLS: igntypes.TLS{ + CertificateAuthorities: certificateAuthorities, + }, + } + } + data, err := json.Marshal(a.Config) if err != nil { return errors.Wrap(err, "failed to Marshal Ignition config") diff --git a/pkg/asset/ignition/machine/node.go b/pkg/asset/ignition/machine/node.go index 9cdefca7978..e0368f7ebf1 100644 --- a/pkg/asset/ignition/machine/node.go +++ b/pkg/asset/ignition/machine/node.go @@ -13,6 +13,20 @@ import ( // pointerIgnitionConfig generates a config which references the remote config // served by the machine config server. func pointerIgnitionConfig(installConfig *types.InstallConfig, rootCA []byte, role string, query string) *ignition.Config { + certificateAuthorities := []ignition.CaReference{{ + Source: dataurl.EncodeBytes(rootCA), + }} + + authorities := []string{} // FIXME: set from installConfig.Machines[*].CertificateAuthorities + if len(authorities) == 0 { + authorities = installConfig.DefaultCertificateAuthorities + } + for _, certificateAuthority := range authorities { + certificateAuthorities = append(certificateAuthorities, ignition.CaReference{ + Source: dataurl.EncodeBytes([]byte(certificateAuthority)), + }) + } + return &ignition.Config{ Ignition: ignition.Ignition{ Version: ignition.MaxVersion.String(), @@ -30,9 +44,7 @@ func pointerIgnitionConfig(installConfig *types.InstallConfig, rootCA []byte, ro }, Security: ignition.Security{ TLS: ignition.TLS{ - CertificateAuthorities: []ignition.CaReference{{ - Source: dataurl.EncodeBytes(rootCA), - }}, + CertificateAuthorities: certificateAuthorities, }, }, }, diff --git a/pkg/asset/installconfig/installconfig.go b/pkg/asset/installconfig/installconfig.go index 286cd8258c2..5860515508e 100644 --- a/pkg/asset/installconfig/installconfig.go +++ b/pkg/asset/installconfig/installconfig.go @@ -2,6 +2,7 @@ package installconfig import ( "net" + "os" "github.com/apparentlymart/go-cidr/cidr" "github.com/ghodss/yaml" @@ -108,6 +109,11 @@ func (a *InstallConfig) Generate(parents asset.Parents) error { panic("unknown platform type") } + certificateAuthority := os.Getenv("_FIXME_OPENSHIFT_INSTALL_CERTIFICATE_AUTHORITY") + if certificateAuthority != "" { + a.Config.DefaultCertificateAuthorities = []string{certificateAuthority} + } + a.Config.Machines = []types.MachinePool{ { Name: "master", diff --git a/pkg/types/installconfig.go b/pkg/types/installconfig.go index 7daa719ea64..d8a8ce05646 100644 --- a/pkg/types/installconfig.go +++ b/pkg/types/installconfig.go @@ -29,6 +29,12 @@ type InstallConfig struct { // Machines is the list of MachinePools that need to be installed. Machines []MachinePool `json:"machines"` + // DefaultCertificateAuthorities is the default slice of additional + // PEM-encoded certificated to add to machines (in addition to the + // system authorities) when MachinePool.CertificateAuthorities is + // empty. + DefaultCertificateAuthorities []string `json:"defaultCertificateAuthorities,omitempty"` + // Platform is the configuration for the specific platform upon which to // perform the installation. Platform `json:"platform"` diff --git a/pkg/types/machinepools.go b/pkg/types/machinepools.go index 884092fd1cb..193f80c5405 100644 --- a/pkg/types/machinepools.go +++ b/pkg/types/machinepools.go @@ -11,6 +11,11 @@ type MachinePool struct { // Platform is configuration for machine pool specific to the platfrom. Platform MachinePoolPlatform `json:"platform"` + + // CertificateAuthorities is a slice of additional PEM-encoded + // certificates to add to machines (in addition to the system + // authorities). + CertificateAuthorities []string `json:"certificateAuthorities,omitempty"` } // MachinePoolPlatform is the platform-specific configuration for a machine