Support for adding ExternalCaCert secrets (#576)
This commit is contained in:
@@ -35,6 +35,9 @@ import (
|
||||
// swagger:model tlsConfiguration
|
||||
type TLSConfiguration struct {
|
||||
|
||||
// ca certificates
|
||||
CaCertificates []string `json:"ca_certificates"`
|
||||
|
||||
// console
|
||||
Console *KeyPairConfiguration `json:"console,omitempty"`
|
||||
|
||||
|
||||
@@ -253,6 +253,15 @@ const AddTenant = ({
|
||||
encoded_cert: "",
|
||||
},
|
||||
]);
|
||||
const [caCertificates, setCaCertificates] = useState<KeyPair[]>([
|
||||
{
|
||||
id: Date.now().toString(),
|
||||
key: "",
|
||||
cert: "",
|
||||
encoded_key: "",
|
||||
encoded_cert: "",
|
||||
},
|
||||
]);
|
||||
const [consoleKeyVal, setConsoleKeyVal] = useState<string>("");
|
||||
const [consoleCertVal, setConsoleCertVal] = useState<string>("");
|
||||
const [serverKeyVal, setServerKeyVal] = useState<string>("");
|
||||
@@ -264,7 +273,49 @@ const AddTenant = ({
|
||||
const [vaultCAVal, setVaultCAVal] = useState<string>("");
|
||||
const [gemaltoCAVal, setGemaltoCAVal] = useState<string>("");
|
||||
|
||||
// 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 = ({
|
||||
<br />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
variant="overline"
|
||||
display="block"
|
||||
gutterBottom
|
||||
>
|
||||
CA Certificates
|
||||
</Typography>
|
||||
</Grid>
|
||||
{caCertificates.map((keyPair: KeyPair) => (
|
||||
<React.Fragment key={keyPair.id}>
|
||||
<Grid item xs={10}>
|
||||
<FileSelector
|
||||
onChange={(encodedValue, fileName) => {
|
||||
addFileToCaCertificates(
|
||||
keyPair.id,
|
||||
"cert",
|
||||
fileName,
|
||||
encodedValue
|
||||
);
|
||||
}}
|
||||
accept=".cer,.crt,.cert,.pem"
|
||||
id="tlsCert"
|
||||
name="tlsCert"
|
||||
label="Cert"
|
||||
value={keyPair.cert}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={1}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
deleteCaCertificate(keyPair.id);
|
||||
}}
|
||||
color="secondary"
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
))}
|
||||
<Grid item xs={12}>
|
||||
<Button onClick={addCaCertificate} color="primary">
|
||||
Add More
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
<Divider />
|
||||
<br />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
|
||||
@@ -701,7 +701,29 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
minInst.Spec.KES.Annotations = tenantReq.Encryption.Annotations
|
||||
minInst.Spec.KES.NodeSelector = tenantReq.Encryption.NodeSelector
|
||||
}
|
||||
|
||||
// External TLS CA certificates for MinIO
|
||||
if tenantReq.TLS != nil && len(tenantReq.TLS.CaCertificates) > 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
|
||||
|
||||
@@ -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",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -3130,6 +3130,10 @@ definitions:
|
||||
console:
|
||||
type: object
|
||||
$ref: "#/definitions/keyPairConfiguration"
|
||||
ca_certificates:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
idpConfiguration:
|
||||
type: object
|
||||
|
||||
Reference in New Issue
Block a user