Support for adding ExternalCaCert secrets (#576)
This commit is contained in:
@@ -35,6 +35,9 @@ import (
|
|||||||
// swagger:model tlsConfiguration
|
// swagger:model tlsConfiguration
|
||||||
type TLSConfiguration struct {
|
type TLSConfiguration struct {
|
||||||
|
|
||||||
|
// ca certificates
|
||||||
|
CaCertificates []string `json:"ca_certificates"`
|
||||||
|
|
||||||
// console
|
// console
|
||||||
Console *KeyPairConfiguration `json:"console,omitempty"`
|
Console *KeyPairConfiguration `json:"console,omitempty"`
|
||||||
|
|
||||||
|
|||||||
@@ -253,6 +253,15 @@ const AddTenant = ({
|
|||||||
encoded_cert: "",
|
encoded_cert: "",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
const [caCertificates, setCaCertificates] = useState<KeyPair[]>([
|
||||||
|
{
|
||||||
|
id: Date.now().toString(),
|
||||||
|
key: "",
|
||||||
|
cert: "",
|
||||||
|
encoded_key: "",
|
||||||
|
encoded_cert: "",
|
||||||
|
},
|
||||||
|
]);
|
||||||
const [consoleKeyVal, setConsoleKeyVal] = useState<string>("");
|
const [consoleKeyVal, setConsoleKeyVal] = useState<string>("");
|
||||||
const [consoleCertVal, setConsoleCertVal] = useState<string>("");
|
const [consoleCertVal, setConsoleCertVal] = useState<string>("");
|
||||||
const [serverKeyVal, setServerKeyVal] = useState<string>("");
|
const [serverKeyVal, setServerKeyVal] = useState<string>("");
|
||||||
@@ -264,7 +273,49 @@ const AddTenant = ({
|
|||||||
const [vaultCAVal, setVaultCAVal] = useState<string>("");
|
const [vaultCAVal, setVaultCAVal] = useState<string>("");
|
||||||
const [gemaltoCAVal, setGemaltoCAVal] = 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 = () => {
|
const addKeyPair = () => {
|
||||||
setMinioCertificates((currentCertificates) => [
|
setMinioCertificates((currentCertificates) => [
|
||||||
...currentCertificates,
|
...currentCertificates,
|
||||||
@@ -941,6 +992,16 @@ const AddTenant = ({
|
|||||||
|
|
||||||
let tenantCerts: any = null;
|
let tenantCerts: any = null;
|
||||||
let consoleCerts: 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) {
|
if (minioCertificates.length > 0) {
|
||||||
tenantCerts = {
|
tenantCerts = {
|
||||||
minio: minioCertificates
|
minio: minioCertificates
|
||||||
@@ -961,12 +1022,13 @@ const AddTenant = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tenantCerts || consoleCerts) {
|
if (tenantCerts || consoleCerts || caCerts) {
|
||||||
dataSend = {
|
dataSend = {
|
||||||
...dataSend,
|
...dataSend,
|
||||||
tls: {
|
tls: {
|
||||||
...tenantCerts,
|
...tenantCerts,
|
||||||
...consoleCerts,
|
...consoleCerts,
|
||||||
|
...caCerts,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1775,6 +1837,60 @@ const AddTenant = ({
|
|||||||
<br />
|
<br />
|
||||||
</Grid>
|
</Grid>
|
||||||
</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 container>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Typography
|
<Typography
|
||||||
|
|||||||
@@ -701,7 +701,29 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
minInst.Spec.KES.Annotations = tenantReq.Encryption.Annotations
|
minInst.Spec.KES.Annotations = tenantReq.Encryption.Annotations
|
||||||
minInst.Spec.KES.NodeSelector = tenantReq.Encryption.NodeSelector
|
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
|
// optionals are set below
|
||||||
var consoleAccess string
|
var consoleAccess string
|
||||||
var consoleSecret string
|
var consoleSecret string
|
||||||
|
|||||||
@@ -227,17 +227,58 @@ func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, e
|
|||||||
return kesConfiguration, nil
|
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
|
// 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
|
// 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) {
|
func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClientI, ns string, keyPairs []*models.KeyPairConfiguration, secretName, tenantName string) ([]*miniov2.LocalCertificateReference, error) {
|
||||||
var keyPairSecrets []*miniov2.LocalCertificateReference
|
var keyPairSecrets []*miniov2.LocalCertificateReference
|
||||||
for i, keyPair := range keyPairs {
|
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 == "" {
|
if keyPair == nil || keyPair.Crt == nil || keyPair.Key == nil || *keyPair.Crt == "" || *keyPair.Key == "" {
|
||||||
return nil, errors.New("certificate files must not be empty")
|
return nil, errors.New("certificate files must not be empty")
|
||||||
}
|
}
|
||||||
// delete secret with same name if exists
|
// 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 {
|
if err != nil {
|
||||||
// log the error if any and continue
|
// log the error if any and continue
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@@ -253,7 +294,7 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient
|
|||||||
}
|
}
|
||||||
externalTLSCertificateSecret := &corev1.Secret{
|
externalTLSCertificateSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: secretName,
|
Name: keyPairSecretName,
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
miniov2.TenantLabel: tenantName,
|
miniov2.TenantLabel: tenantName,
|
||||||
},
|
},
|
||||||
@@ -271,7 +312,7 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient
|
|||||||
}
|
}
|
||||||
// Certificates used by the minio instance
|
// Certificates used by the minio instance
|
||||||
keyPairSecrets = append(keyPairSecrets, &miniov2.LocalCertificateReference{
|
keyPairSecrets = append(keyPairSecrets, &miniov2.LocalCertificateReference{
|
||||||
Name: secretName,
|
Name: keyPairSecretName,
|
||||||
Type: "kubernetes.io/tls",
|
Type: "kubernetes.io/tls",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5267,6 +5267,12 @@ func init() {
|
|||||||
"tlsConfiguration": {
|
"tlsConfiguration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"ca_certificates": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"console": {
|
"console": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"$ref": "#/definitions/keyPairConfiguration"
|
"$ref": "#/definitions/keyPairConfiguration"
|
||||||
@@ -11159,6 +11165,12 @@ func init() {
|
|||||||
"tlsConfiguration": {
|
"tlsConfiguration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"ca_certificates": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"console": {
|
"console": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"$ref": "#/definitions/keyPairConfiguration"
|
"$ref": "#/definitions/keyPairConfiguration"
|
||||||
|
|||||||
@@ -3130,6 +3130,10 @@ definitions:
|
|||||||
console:
|
console:
|
||||||
type: object
|
type: object
|
||||||
$ref: "#/definitions/keyPairConfiguration"
|
$ref: "#/definitions/keyPairConfiguration"
|
||||||
|
ca_certificates:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
|
||||||
idpConfiguration:
|
idpConfiguration:
|
||||||
type: object
|
type: object
|
||||||
|
|||||||
Reference in New Issue
Block a user