Skip to content

Commit

Permalink
WiP: Support CA certificate provided by user
Browse files Browse the repository at this point in the history
In order to allow users to use self-signed certificates when
authenticating into OpenStack cloud, we need to make sure CA certificate
provided to the installer by the user is actually used by CNO and Kuryr.

In case of CNO this commit makes sure to configure gophercloud's HTTP
client to use the user CA when provided.

In case of Kuryr the CA certificate is injected into kuryr-controller's
/etc/ssl/certs.
  • Loading branch information
dulek committed Jan 16, 2020
1 parent 632a7f7 commit 692922b
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 4 deletions.
7 changes: 7 additions & 0 deletions bindata/network/kuryr/004-user-ca-cert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: user-ca-certificate
namespace: openshift-kuryr
data:
user-ca-bundle.crt: "{{ .UserCACertificate }}"
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ spec:
volumeMounts:
- name: config-volume
mountPath: "/etc/kuryr"
- name: user-ca-certificate-volume
subPath: user-ca-bundle.crt
mountPath: /etc/ssl/certs/user-ca-bundle.crt
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
Expand All @@ -68,3 +71,6 @@ spec:
- name: config-volume
configMap:
name: kuryr-config
- name: user-ca-certificate-volume
configMap:
name: user-ca-certificate
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions pkg/bootstrap/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type KuryrBootstrapResult struct {
WebhookCAKey string
WebhookCert string
WebhookKey string
UserCACert string
}

type OVNBootstrapResult struct {
Expand Down
3 changes: 3 additions & 0 deletions pkg/network/kuryr.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func renderKuryr(conf *operv1.NetworkSpec, bootstrapResult *bootstrap.BootstrapR
data := render.MakeRenderData()
data.Data["ReleaseVersion"] = os.Getenv("RELEASE_VERSION")

// OpenStack cloud CA certificate provided by the user to the installer
data.Data["UserCACertificate"] = b.UserCACert

// general kuryr options
data.Data["ResourceTags"] = "openshiftClusterID=" + b.ClusterID
data.Data["PodSecurityGroups"] = strings.Join(b.PodSecurityGroups, ",")
Expand Down
48 changes: 44 additions & 4 deletions pkg/platform/openstack/kuryr_bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package openstack

import (
"context"
"crypto/tls"
"crypto/x509"
b64 "encoding/base64"
"fmt"
"github.com/openshift/cluster-network-operator/pkg/bootstrap"
"k8s.io/api/core/v1"
"log"
"net"
"net/http"
"regexp"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"
Expand Down Expand Up @@ -44,9 +47,11 @@ import (
)

const (
CloudsSecret = "installer-cloud-credentials"
CloudName = "openstack"
CloudsSecretKey = "clouds.yaml"
CloudsSecret = "installer-cloud-credentials"
CloudName = "openstack"
CloudsSecretKey = "clouds.yaml"
OpenShiftConfigNamespace = "openshift-config"
UserCABundleConfigMap = "user-ca-bundle"
// NOTE(dulek): This one is hardcoded in openshift/installer.
InfrastructureCRDName = "cluster"
MinOctaviaVersionWithHTTPSMonitors = "v2.10"
Expand Down Expand Up @@ -814,6 +819,18 @@ func ensureCertificate(kubeClient client.Client, caPEM []byte, privateKey []byte
}
}

func getUserCACert(kubeClient client.Client) (string, error) {
cm := &v1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
ObjectMeta: metav1.ObjectMeta{Name: UserCABundleConfigMap},
}
err := kubeClient.Get(context.TODO(), client.ObjectKey{Namespace: OpenShiftConfigNamespace, Name: UserCABundleConfigMap}, cm)
if err != nil {
return "", err
}
return string(cm.Data["ca-bundle.crt"]), nil
}

// Logs into OpenStack and creates all the resources that are required to run
// Kuryr based on conf NetworkConfigSpec. Basically this includes service
// network and subnet, pods subnetpool, security group and load balancer for
Expand Down Expand Up @@ -849,8 +866,30 @@ func BootstrapKuryr(conf *operv1.NetworkSpec, kubeClient client.Client) (*bootst
if err != nil {
return nil, errors.Wrap(err, "failed to authenticate to OpenStack")
}
provider, err := openstack.NewClient(opts.IdentityEndpoint)
if err != nil {
return nil, errors.Wrap(err, "failed to authenticate to OpenStack")
}

// We need to fetch user-provided OpenStack cloud CA certificate and make gophercloud use it.
// Also it'll get injected into a ConfigMap mounted into kuryr-controller later on.
userCACert, err := getUserCACert(kubeClient)
if userCACert != "" {
certPool, err := x509.SystemCertPool()
if err == nil {
certPool.AppendCertsFromPEM([]byte(userCACert))
client := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
},
}
provider.HTTPClient = client
}
}

provider, err := openstack.AuthenticatedClient(*opts)
err = openstack.Authenticate(provider, *opts)
if err != nil {
return nil, errors.Wrap(err, "failed to authenticate to OpenStack")
}
Expand Down Expand Up @@ -1123,6 +1162,7 @@ func BootstrapKuryr(conf *operv1.NetworkSpec, kubeClient client.Client) (*bootst
WebhookCAKey: b64.StdEncoding.EncodeToString(key),
WebhookKey: b64.StdEncoding.EncodeToString(webhookKey),
WebhookCert: b64.StdEncoding.EncodeToString(webhookCert),
UserCACert: userCACert,
}}
return &res, nil
}

0 comments on commit 692922b

Please sign in to comment.