Skip to content

Commit 1c6a29b

Browse files
authored
Support for adding ExternalCaCert secrets (#576)
1 parent 6b02f47 commit 1c6a29b

File tree

6 files changed

+205
-7
lines changed

6 files changed

+205
-7
lines changed

models/tls_configuration.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

portal-ui/src/screens/Console/Tenants/ListTenants/AddTenant.tsx

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ const AddTenant = ({
253253
encoded_cert: "",
254254
},
255255
]);
256+
const [caCertificates, setCaCertificates] = useState<KeyPair[]>([
257+
{
258+
id: Date.now().toString(),
259+
key: "",
260+
cert: "",
261+
encoded_key: "",
262+
encoded_cert: "",
263+
},
264+
]);
256265
const [consoleKeyVal, setConsoleKeyVal] = useState<string>("");
257266
const [consoleCertVal, setConsoleCertVal] = useState<string>("");
258267
const [serverKeyVal, setServerKeyVal] = useState<string>("");
@@ -264,7 +273,49 @@ const AddTenant = ({
264273
const [vaultCAVal, setVaultCAVal] = useState<string>("");
265274
const [gemaltoCAVal, setGemaltoCAVal] = useState<string>("");
266275

267-
// Certificates functions
276+
// CA Certificates functions
277+
const addCaCertificate = () => {
278+
setCaCertificates((currentCertificates) => [
279+
...currentCertificates,
280+
{
281+
id: Date.now().toString(),
282+
key: "",
283+
cert: "",
284+
encoded_key: "",
285+
encoded_cert: "",
286+
},
287+
]);
288+
};
289+
290+
const deleteCaCertificate = (id: string) => {
291+
if (caCertificates.length > 1) {
292+
setCaCertificates(
293+
caCertificates.filter((item: KeyPair) => item.id !== id)
294+
);
295+
}
296+
};
297+
298+
const addFileToCaCertificates = (
299+
id: string,
300+
key: string,
301+
fileName: string,
302+
value: string
303+
) => {
304+
setCaCertificates(
305+
caCertificates.map((item: KeyPair) => {
306+
if (item.id === id) {
307+
return {
308+
...item,
309+
[key]: fileName,
310+
[`encoded_${key}`]: value,
311+
};
312+
}
313+
return item;
314+
})
315+
);
316+
};
317+
318+
// KeyPair Certificates functions
268319
const addKeyPair = () => {
269320
setMinioCertificates((currentCertificates) => [
270321
...currentCertificates,
@@ -941,6 +992,16 @@ const AddTenant = ({
941992

942993
let tenantCerts: any = null;
943994
let consoleCerts: any = null;
995+
let caCerts: any = null;
996+
997+
if (caCertificates.length > 0) {
998+
caCerts = {
999+
ca_certificates: caCertificates
1000+
.map((keyPair: KeyPair) => keyPair.encoded_cert)
1001+
.filter((keyPair) => keyPair),
1002+
};
1003+
}
1004+
9441005
if (minioCertificates.length > 0) {
9451006
tenantCerts = {
9461007
minio: minioCertificates
@@ -961,12 +1022,13 @@ const AddTenant = ({
9611022
};
9621023
}
9631024

964-
if (tenantCerts || consoleCerts) {
1025+
if (tenantCerts || consoleCerts || caCerts) {
9651026
dataSend = {
9661027
...dataSend,
9671028
tls: {
9681029
...tenantCerts,
9691030
...consoleCerts,
1031+
...caCerts,
9701032
},
9711033
};
9721034
}
@@ -1775,6 +1837,60 @@ const AddTenant = ({
17751837
<br />
17761838
</Grid>
17771839
</Grid>
1840+
<Grid container>
1841+
<Grid item xs={12}>
1842+
<Typography
1843+
variant="overline"
1844+
display="block"
1845+
gutterBottom
1846+
>
1847+
CA Certificates
1848+
</Typography>
1849+
</Grid>
1850+
{caCertificates.map((keyPair: KeyPair) => (
1851+
<React.Fragment key={keyPair.id}>
1852+
<Grid item xs={10}>
1853+
<FileSelector
1854+
onChange={(encodedValue, fileName) => {
1855+
addFileToCaCertificates(
1856+
keyPair.id,
1857+
"cert",
1858+
fileName,
1859+
encodedValue
1860+
);
1861+
}}
1862+
accept=".cer,.crt,.cert,.pem"
1863+
id="tlsCert"
1864+
name="tlsCert"
1865+
label="Cert"
1866+
value={keyPair.cert}
1867+
/>
1868+
</Grid>
1869+
<Grid item xs={1}>
1870+
<Button
1871+
onClick={() => {
1872+
deleteCaCertificate(keyPair.id);
1873+
}}
1874+
color="secondary"
1875+
>
1876+
Remove
1877+
</Button>
1878+
</Grid>
1879+
</React.Fragment>
1880+
))}
1881+
<Grid item xs={12}>
1882+
<Button onClick={addCaCertificate} color="primary">
1883+
Add More
1884+
</Button>
1885+
</Grid>
1886+
</Grid>
1887+
<Grid container>
1888+
<Grid item xs={12}>
1889+
<br />
1890+
<Divider />
1891+
<br />
1892+
</Grid>
1893+
</Grid>
17781894
<Grid container>
17791895
<Grid item xs={12}>
17801896
<Typography

restapi/admin_tenants.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,29 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
701701
minInst.Spec.KES.Annotations = tenantReq.Encryption.Annotations
702702
minInst.Spec.KES.NodeSelector = tenantReq.Encryption.NodeSelector
703703
}
704-
704+
// External TLS CA certificates for MinIO
705+
if tenantReq.TLS != nil && len(tenantReq.TLS.CaCertificates) > 0 {
706+
var caCertificates []tenantSecret
707+
for i, caCertificate := range tenantReq.TLS.CaCertificates {
708+
certificateContent, err := base64.StdEncoding.DecodeString(caCertificate)
709+
if err != nil {
710+
return nil, prepareError(errorGeneric, nil, err)
711+
}
712+
caCertificates = append(caCertificates, tenantSecret{
713+
Name: fmt.Sprintf("ca-certificate-%d", i),
714+
Content: map[string][]byte{
715+
"public.crt": certificateContent,
716+
},
717+
})
718+
}
719+
if len(caCertificates) > 0 {
720+
certificateSecrets, err := createOrReplaceSecrets(ctx, &k8sClient, ns, caCertificates, tenantName)
721+
if err != nil {
722+
return nil, prepareError(errorGeneric, nil, err)
723+
}
724+
minInst.Spec.ExternalCaCertSecret = certificateSecrets
725+
}
726+
}
705727
// optionals are set below
706728
var consoleAccess string
707729
var consoleSecret string

restapi/admin_tenants_helper.go

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,58 @@ func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, e
227227
return kesConfiguration, nil
228228
}
229229

230+
type tenantSecret struct {
231+
Name string
232+
Content map[string][]byte
233+
}
234+
235+
// createOrReplaceSecrets receives an array of Tenant Secrets to be stored as k8s secrets
236+
func createOrReplaceSecrets(ctx context.Context, clientSet K8sClientI, ns string, secrets []tenantSecret, tenantName string) ([]*miniov2.LocalCertificateReference, error) {
237+
var k8sSecrets []*miniov2.LocalCertificateReference
238+
for _, secret := range secrets {
239+
if len(secret.Content) > 0 && secret.Name != "" {
240+
// delete secret with same name if exists
241+
err := clientSet.deleteSecret(ctx, ns, secret.Name, metav1.DeleteOptions{})
242+
if err != nil {
243+
// log the error if any and continue
244+
log.Println(err)
245+
}
246+
imm := true
247+
k8sSecret := &corev1.Secret{
248+
ObjectMeta: metav1.ObjectMeta{
249+
Name: secret.Name,
250+
Labels: map[string]string{
251+
miniov2.TenantLabel: tenantName,
252+
},
253+
},
254+
Type: corev1.SecretTypeOpaque,
255+
Immutable: &imm,
256+
Data: secret.Content,
257+
}
258+
_, err = clientSet.createSecret(ctx, ns, k8sSecret, metav1.CreateOptions{})
259+
if err != nil {
260+
return nil, err
261+
}
262+
k8sSecrets = append(k8sSecrets, &miniov2.LocalCertificateReference{
263+
Name: secret.Name,
264+
Type: "Opaque",
265+
})
266+
}
267+
}
268+
return k8sSecrets, nil
269+
}
270+
230271
// createOrReplaceExternalCertSecrets receives an array of KeyPairs (public and private key), encoded in base64, decode it and generate an equivalent number of kubernetes
231272
// secrets to be used by the miniov2 for TLS encryption
232273
func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClientI, ns string, keyPairs []*models.KeyPairConfiguration, secretName, tenantName string) ([]*miniov2.LocalCertificateReference, error) {
233274
var keyPairSecrets []*miniov2.LocalCertificateReference
234275
for i, keyPair := range keyPairs {
235-
secretName := fmt.Sprintf("%s-%d", secretName, i)
276+
keyPairSecretName := fmt.Sprintf("%s-%d", secretName, i)
236277
if keyPair == nil || keyPair.Crt == nil || keyPair.Key == nil || *keyPair.Crt == "" || *keyPair.Key == "" {
237278
return nil, errors.New("certificate files must not be empty")
238279
}
239280
// delete secret with same name if exists
240-
err := clientSet.deleteSecret(ctx, ns, fmt.Sprintf("%s-%d", secretName, i), metav1.DeleteOptions{})
281+
err := clientSet.deleteSecret(ctx, ns, keyPairSecretName, metav1.DeleteOptions{})
241282
if err != nil {
242283
// log the error if any and continue
243284
log.Println(err)
@@ -253,7 +294,7 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient
253294
}
254295
externalTLSCertificateSecret := &corev1.Secret{
255296
ObjectMeta: metav1.ObjectMeta{
256-
Name: secretName,
297+
Name: keyPairSecretName,
257298
Labels: map[string]string{
258299
miniov2.TenantLabel: tenantName,
259300
},
@@ -271,7 +312,7 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient
271312
}
272313
// Certificates used by the minio instance
273314
keyPairSecrets = append(keyPairSecrets, &miniov2.LocalCertificateReference{
274-
Name: secretName,
315+
Name: keyPairSecretName,
275316
Type: "kubernetes.io/tls",
276317
})
277318
}

restapi/embedded_spec.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

swagger.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3130,6 +3130,10 @@ definitions:
31303130
console:
31313131
type: object
31323132
$ref: "#/definitions/keyPairConfiguration"
3133+
ca_certificates:
3134+
type: array
3135+
items:
3136+
type: string
31333137

31343138
idpConfiguration:
31353139
type: object

0 commit comments

Comments
 (0)