From 1c6a29bc20bad3cd9336e05aa7a0041589316b72 Mon Sep 17 00:00:00 2001 From: Lenin Alevski Date: Tue, 2 Feb 2021 18:49:40 -0600 Subject: [PATCH] Support for adding ExternalCaCert secrets (#576) --- models/tls_configuration.go | 3 + .../Console/Tenants/ListTenants/AddTenant.tsx | 120 +++++++++++++++++- restapi/admin_tenants.go | 24 +++- restapi/admin_tenants_helper.go | 49 ++++++- restapi/embedded_spec.go | 12 ++ swagger.yml | 4 + 6 files changed, 205 insertions(+), 7 deletions(-) diff --git a/models/tls_configuration.go b/models/tls_configuration.go index e4ec47ec2..8f6dd6461 100644 --- a/models/tls_configuration.go +++ b/models/tls_configuration.go @@ -35,6 +35,9 @@ import ( // swagger:model tlsConfiguration type TLSConfiguration struct { + // ca certificates + CaCertificates []string `json:"ca_certificates"` + // console Console *KeyPairConfiguration `json:"console,omitempty"` diff --git a/portal-ui/src/screens/Console/Tenants/ListTenants/AddTenant.tsx b/portal-ui/src/screens/Console/Tenants/ListTenants/AddTenant.tsx index 114b43b9f..d7f828a4b 100644 --- a/portal-ui/src/screens/Console/Tenants/ListTenants/AddTenant.tsx +++ b/portal-ui/src/screens/Console/Tenants/ListTenants/AddTenant.tsx @@ -253,6 +253,15 @@ const AddTenant = ({ encoded_cert: "", }, ]); + const [caCertificates, setCaCertificates] = useState([ + { + id: Date.now().toString(), + key: "", + cert: "", + encoded_key: "", + encoded_cert: "", + }, + ]); const [consoleKeyVal, setConsoleKeyVal] = useState(""); const [consoleCertVal, setConsoleCertVal] = useState(""); const [serverKeyVal, setServerKeyVal] = useState(""); @@ -264,7 +273,49 @@ const AddTenant = ({ const [vaultCAVal, setVaultCAVal] = useState(""); const [gemaltoCAVal, setGemaltoCAVal] = useState(""); - // Certificates functions + // CA Certificates functions + const addCaCertificate = () => { + setCaCertificates((currentCertificates) => [ + ...currentCertificates, + { + id: Date.now().toString(), + key: "", + cert: "", + encoded_key: "", + encoded_cert: "", + }, + ]); + }; + + const deleteCaCertificate = (id: string) => { + if (caCertificates.length > 1) { + setCaCertificates( + caCertificates.filter((item: KeyPair) => item.id !== id) + ); + } + }; + + const addFileToCaCertificates = ( + id: string, + key: string, + fileName: string, + value: string + ) => { + setCaCertificates( + caCertificates.map((item: KeyPair) => { + if (item.id === id) { + return { + ...item, + [key]: fileName, + [`encoded_${key}`]: value, + }; + } + return item; + }) + ); + }; + + // KeyPair Certificates functions const addKeyPair = () => { setMinioCertificates((currentCertificates) => [ ...currentCertificates, @@ -941,6 +992,16 @@ const AddTenant = ({ let tenantCerts: any = null; let consoleCerts: any = null; + let caCerts: any = null; + + if (caCertificates.length > 0) { + caCerts = { + ca_certificates: caCertificates + .map((keyPair: KeyPair) => keyPair.encoded_cert) + .filter((keyPair) => keyPair), + }; + } + if (minioCertificates.length > 0) { tenantCerts = { minio: minioCertificates @@ -961,12 +1022,13 @@ const AddTenant = ({ }; } - if (tenantCerts || consoleCerts) { + if (tenantCerts || consoleCerts || caCerts) { dataSend = { ...dataSend, tls: { ...tenantCerts, ...consoleCerts, + ...caCerts, }, }; } @@ -1775,6 +1837,60 @@ const AddTenant = ({
+ + + + CA Certificates + + + {caCertificates.map((keyPair: KeyPair) => ( + + + { + addFileToCaCertificates( + keyPair.id, + "cert", + fileName, + encodedValue + ); + }} + accept=".cer,.crt,.cert,.pem" + id="tlsCert" + name="tlsCert" + label="Cert" + value={keyPair.cert} + /> + + + + + + ))} + + + + + + +
+ +
+
+
0 { + var caCertificates []tenantSecret + for i, caCertificate := range tenantReq.TLS.CaCertificates { + certificateContent, err := base64.StdEncoding.DecodeString(caCertificate) + if err != nil { + return nil, prepareError(errorGeneric, nil, err) + } + caCertificates = append(caCertificates, tenantSecret{ + Name: fmt.Sprintf("ca-certificate-%d", i), + Content: map[string][]byte{ + "public.crt": certificateContent, + }, + }) + } + if len(caCertificates) > 0 { + certificateSecrets, err := createOrReplaceSecrets(ctx, &k8sClient, ns, caCertificates, tenantName) + if err != nil { + return nil, prepareError(errorGeneric, nil, err) + } + minInst.Spec.ExternalCaCertSecret = certificateSecrets + } + } // optionals are set below var consoleAccess string var consoleSecret string diff --git a/restapi/admin_tenants_helper.go b/restapi/admin_tenants_helper.go index a03a0dd63..798edad55 100644 --- a/restapi/admin_tenants_helper.go +++ b/restapi/admin_tenants_helper.go @@ -227,17 +227,58 @@ func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, e return kesConfiguration, nil } +type tenantSecret struct { + Name string + Content map[string][]byte +} + +// createOrReplaceSecrets receives an array of Tenant Secrets to be stored as k8s secrets +func createOrReplaceSecrets(ctx context.Context, clientSet K8sClientI, ns string, secrets []tenantSecret, tenantName string) ([]*miniov2.LocalCertificateReference, error) { + var k8sSecrets []*miniov2.LocalCertificateReference + for _, secret := range secrets { + if len(secret.Content) > 0 && secret.Name != "" { + // delete secret with same name if exists + err := clientSet.deleteSecret(ctx, ns, secret.Name, metav1.DeleteOptions{}) + if err != nil { + // log the error if any and continue + log.Println(err) + } + imm := true + k8sSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secret.Name, + Labels: map[string]string{ + miniov2.TenantLabel: tenantName, + }, + }, + Type: corev1.SecretTypeOpaque, + Immutable: &imm, + Data: secret.Content, + } + _, err = clientSet.createSecret(ctx, ns, k8sSecret, metav1.CreateOptions{}) + if err != nil { + return nil, err + } + k8sSecrets = append(k8sSecrets, &miniov2.LocalCertificateReference{ + Name: secret.Name, + Type: "Opaque", + }) + } + } + return k8sSecrets, nil +} + // createOrReplaceExternalCertSecrets receives an array of KeyPairs (public and private key), encoded in base64, decode it and generate an equivalent number of kubernetes // secrets to be used by the miniov2 for TLS encryption func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClientI, ns string, keyPairs []*models.KeyPairConfiguration, secretName, tenantName string) ([]*miniov2.LocalCertificateReference, error) { var keyPairSecrets []*miniov2.LocalCertificateReference for i, keyPair := range keyPairs { - secretName := fmt.Sprintf("%s-%d", secretName, i) + keyPairSecretName := fmt.Sprintf("%s-%d", secretName, i) if keyPair == nil || keyPair.Crt == nil || keyPair.Key == nil || *keyPair.Crt == "" || *keyPair.Key == "" { return nil, errors.New("certificate files must not be empty") } // delete secret with same name if exists - err := clientSet.deleteSecret(ctx, ns, fmt.Sprintf("%s-%d", secretName, i), metav1.DeleteOptions{}) + err := clientSet.deleteSecret(ctx, ns, keyPairSecretName, metav1.DeleteOptions{}) if err != nil { // log the error if any and continue log.Println(err) @@ -253,7 +294,7 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient } externalTLSCertificateSecret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: keyPairSecretName, Labels: map[string]string{ miniov2.TenantLabel: tenantName, }, @@ -271,7 +312,7 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient } // Certificates used by the minio instance keyPairSecrets = append(keyPairSecrets, &miniov2.LocalCertificateReference{ - Name: secretName, + Name: keyPairSecretName, Type: "kubernetes.io/tls", }) } diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index c7790a9e8..7a4439645 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -5267,6 +5267,12 @@ func init() { "tlsConfiguration": { "type": "object", "properties": { + "ca_certificates": { + "type": "array", + "items": { + "type": "string" + } + }, "console": { "type": "object", "$ref": "#/definitions/keyPairConfiguration" @@ -11159,6 +11165,12 @@ func init() { "tlsConfiguration": { "type": "object", "properties": { + "ca_certificates": { + "type": "array", + "items": { + "type": "string" + } + }, "console": { "type": "object", "$ref": "#/definitions/keyPairConfiguration" diff --git a/swagger.yml b/swagger.yml index 0679e90fa..1238cf1f5 100644 --- a/swagger.yml +++ b/swagger.yml @@ -3130,6 +3130,10 @@ definitions: console: type: object $ref: "#/definitions/keyPairConfiguration" + ca_certificates: + type: array + items: + type: string idpConfiguration: type: object