Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tls-pkcs12-trustore format #387

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/modules/secret-operator/pages/secretclass.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ metadata:
name: admin-credentials-class
spec:
backend:
k8sSearch:
k8sSearch:
searchNamespace:
pod: {}
---
Expand Down
55 changes: 43 additions & 12 deletions rust/operator-binary/src/format/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use snafu::{OptionExt, ResultExt, Snafu};
use crate::format::utils::split_pem_certificates;

use super::{
well_known::{CompatibilityOptions, TlsPem, TlsPkcs12},
well_known::{CompatibilityOptions, TlsCaPem, TlsPem, TlsPkcs12, TlsPkcs12Truststore},
SecretFormat, WellKnownSecretData,
};

Expand All @@ -29,6 +29,35 @@ pub fn convert(
compat.tls_pkcs12_password.as_deref().unwrap_or_default(),
)?))
}
(WellKnownSecretData::TlsPem(pem), SecretFormat::TlsCaPem) => {
Ok(WellKnownSecretData::TlsCaPem(TlsCaPem {
ca_pem: pem.ca_pem,
}))
}
(WellKnownSecretData::TlsPem(pem), SecretFormat::TlsPkcs12Truststore) => {
let ca_stack = ca_pem_to_ca_stack(&pem.ca_pem)?;

Ok(WellKnownSecretData::TlsPkcs12Truststore(
TlsPkcs12Truststore {
truststore: pkcs12_truststore(
&ca_stack,
compat.tls_pkcs12_password.as_deref().unwrap_or_default(),
)?,
},
))
}
(WellKnownSecretData::TlsCaPem(pem), SecretFormat::TlsPkcs12Truststore) => {
let ca_stack = ca_pem_to_ca_stack(&pem.ca_pem)?;

Ok(WellKnownSecretData::TlsPkcs12Truststore(
TlsPkcs12Truststore {
truststore: pkcs12_truststore(
&ca_stack,
compat.tls_pkcs12_password.as_deref().unwrap_or_default(),
)?,
},
))
}

(from, to) => NoValidConversionSnafu { from, to }.fail(),
}
Expand All @@ -49,20 +78,11 @@ pub enum ConvertError {
TlsToPkcs12 { source: TlsToPkcs12Error },
}

pub fn convert_tls_to_pkcs12(
pem: TlsPem,
p12_password: &str,
) -> Result<TlsPkcs12, TlsToPkcs12Error> {
fn convert_tls_to_pkcs12(pem: TlsPem, p12_password: &str) -> Result<TlsPkcs12, TlsToPkcs12Error> {
use tls_to_pkcs12_error::*;
let cert = X509::from_pem(&pem.certificate_pem).context(LoadCertSnafu)?;
let key = PKey::private_key_from_pem(&pem.key_pem).context(LoadKeySnafu)?;

let mut ca_stack = Stack::<X509>::new().context(LoadCaSnafu)?;
for ca in split_pem_certificates(&pem.ca_pem) {
X509::from_pem(ca)
.and_then(|ca| ca_stack.push(ca))
.context(LoadCertSnafu)?;
}
let ca_stack = ca_pem_to_ca_stack(&pem.ca_pem)?;

Ok(TlsPkcs12 {
truststore: pkcs12_truststore(&ca_stack, p12_password)?,
Expand All @@ -76,6 +96,17 @@ pub fn convert_tls_to_pkcs12(
})
}

fn ca_pem_to_ca_stack(ca_pem: &[u8]) -> Result<Stack<X509>, TlsToPkcs12Error> {
use tls_to_pkcs12_error::*;
let mut ca_stack = Stack::<X509>::new().context(LoadCaSnafu)?;
for ca in split_pem_certificates(ca_pem) {
X509::from_pem(ca)
.and_then(|ca| ca_stack.push(ca))
.context(LoadCertSnafu)?;
}
Ok(ca_stack)
}

fn bmp_string(s: &str) -> Vec<u8> {
s.encode_utf16()
.chain([0]) // null-termination character
Expand Down
20 changes: 20 additions & 0 deletions rust/operator-binary/src/format/well_known.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,22 @@ pub struct TlsPem {
pub ca_pem: Vec<u8>,
}

#[derive(Debug)]
pub struct TlsCaPem {
pub ca_pem: Vec<u8>,
}

#[derive(Debug)]
pub struct TlsPkcs12 {
pub keystore: Vec<u8>,
pub truststore: Vec<u8>,
}

#[derive(Debug)]
pub struct TlsPkcs12Truststore {
pub truststore: Vec<u8>,
}

#[derive(Debug)]
pub struct Kerberos {
pub keytab: Vec<u8>,
Expand All @@ -41,7 +51,9 @@ pub struct Kerberos {
)]
pub enum WellKnownSecretData {
TlsPem(TlsPem),
TlsCaPem(TlsCaPem),
TlsPkcs12(TlsPkcs12),
TlsPkcs12Truststore(TlsPkcs12Truststore),
Kerberos(Kerberos),
}

Expand All @@ -58,6 +70,9 @@ impl WellKnownSecretData {
(FILE_PEM_CERT_CA.to_string(), ca_pem),
]
.into(),
WellKnownSecretData::TlsCaPem(TlsCaPem { ca_pem }) => {
[(FILE_PEM_CERT_CA.to_string(), ca_pem)].into()
}
WellKnownSecretData::TlsPkcs12(TlsPkcs12 {
keystore,
truststore,
Expand All @@ -66,6 +81,9 @@ impl WellKnownSecretData {
(FILE_PKCS12_CERT_TRUSTSTORE.to_string(), truststore),
]
.into(),
WellKnownSecretData::TlsPkcs12Truststore(TlsPkcs12Truststore { truststore }) => {
[(FILE_PKCS12_CERT_TRUSTSTORE.to_string(), truststore)].into()
}
WellKnownSecretData::Kerberos(Kerberos { keytab, krb5_conf }) => [
(FILE_KERBEROS_KEYTAB_KEYTAB.to_string(), keytab),
(FILE_KERBEROS_KEYTAB_KRB5_CONF.to_string(), krb5_conf),
Expand All @@ -88,6 +106,8 @@ impl WellKnownSecretData {
key_pem: take_file(FILE_PEM_CERT_KEY)?,
ca_pem: take_file(FILE_PEM_CERT_CA)?,
}))
} else if let Ok(ca_pem) = take_file(SecretFormat::TlsCaPem, FILE_PEM_CERT_CA) {
Ok(WellKnownSecretData::TlsCaPem(TlsCaPem { ca_pem }))
} else if let Ok(keystore) = take_file(SecretFormat::TlsPkcs12, FILE_PKCS12_CERT_KEYSTORE) {
Ok(WellKnownSecretData::TlsPkcs12(TlsPkcs12 {
keystore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ timeout: 300
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer
name: tls-consumer-pem
status:
succeeded: 1
5 changes: 5 additions & 0 deletions tests/templates/kuttl/auto-tls/10-consumer-pem.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: envsubst '$NAMESPACE' < consumer-pem.yaml | kubectl apply -n $NAMESPACE -f -
11 changes: 11 additions & 0 deletions tests/templates/kuttl/auto-tls/11-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 300
---
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer-pkcs12
status:
succeeded: 1
5 changes: 5 additions & 0 deletions tests/templates/kuttl/auto-tls/11-consumer-pkcs12.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: envsubst '$NAMESPACE' < consumer-pkcs12.yaml | kubectl apply -n $NAMESPACE -f -
11 changes: 11 additions & 0 deletions tests/templates/kuttl/auto-tls/12-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 300
---
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer-pkcs12-truststore
status:
succeeded: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: envsubst '$NAMESPACE' < consumer-pkcs12-truststore.yaml | kubectl apply -n $NAMESPACE -f -
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer
name: tls-consumer-pem
spec:
template:
spec:
Expand Down
48 changes: 48 additions & 0 deletions tests/templates/kuttl/auto-tls/consumer-pkcs12-truststore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# $NAMESPACE will be replaced with the namespace of the test case.
---
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer-pkcs12-truststore
spec:
template:
spec:
containers:
- name: consumer
image: docker.stackable.tech/stackable/testing-tools:0.2.0-stackable0.0.0-dev
command:
- bash
args:
- -c
- |
set -euo pipefail
ls -la /stackable/tls

if ! test -f /stackable/tls/truststore.p12; then echo "Truststore missing!" && exit 1; fi
if test -f /stackable/tls/keystore.p12; then echo "Keystore is present, but should be absent!" && exit 1; fi
volumeMounts:
- mountPath: /stackable/tls
name: tls
volumes:
- name: tls
ephemeral:
volumeClaimTemplate:
metadata:
annotations:
secrets.stackable.tech/class: tls-$NAMESPACE
secrets.stackable.tech/scope: pod
secrets.stackable.tech/format: tls-pkcs12-truststore
spec:
storageClassName: secrets.stackable.tech
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "1"
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
restartPolicy: Never
terminationGracePeriodSeconds: 0
serviceAccount: integration-tests-sa
48 changes: 48 additions & 0 deletions tests/templates/kuttl/auto-tls/consumer-pkcs12.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# $NAMESPACE will be replaced with the namespace of the test case.
---
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer-pkcs12
spec:
template:
spec:
containers:
- name: consumer
image: docker.stackable.tech/stackable/testing-tools:0.2.0-stackable0.0.0-dev
command:
- bash
args:
- -c
- |
set -euo pipefail
ls -la /stackable/tls

if ! test -f /stackable/tls/truststore.p12; then echo "Truststore missing!" && exit 1; fi
if ! test -f /stackable/tls/keystore.p12; then echo "Keystore missing!" && exit 1; fi
volumeMounts:
- mountPath: /stackable/tls
name: tls
volumes:
- name: tls
ephemeral:
volumeClaimTemplate:
metadata:
annotations:
secrets.stackable.tech/class: tls-$NAMESPACE
secrets.stackable.tech/scope: pod
secrets.stackable.tech/format: tls-pkcs12
spec:
storageClassName: secrets.stackable.tech
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "1"
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
restartPolicy: Never
terminationGracePeriodSeconds: 0
serviceAccount: integration-tests-sa
5 changes: 0 additions & 5 deletions tests/templates/kuttl/tls/10-consumer.yaml

This file was deleted.

5 changes: 5 additions & 0 deletions tests/templates/kuttl/user-provided-tls/01-secretclass.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: envsubst '$NAMESPACE' < secretclass.yaml | kubectl apply -n "$NAMESPACE" -f -
30 changes: 30 additions & 0 deletions tests/templates/kuttl/user-provided-tls/02-rbac.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: use-integration-tests-scc
rules:
{% if test_scenario['values']['openshift'] == "true" %}
- apiGroups: ["security.openshift.io"]
resources: ["securitycontextconstraints"]
resourceNames: ["privileged"]
verbs: ["use"]
{% endif %}
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: integration-tests-sa
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: use-integration-tests-scc
subjects:
- kind: ServiceAccount
name: integration-tests-sa
roleRef:
kind: Role
name: use-integration-tests-scc
apiGroup: rbac.authorization.k8s.io

11 changes: 11 additions & 0 deletions tests/templates/kuttl/user-provided-tls/10-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 300
---
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer-ca-pem
status:
succeeded: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: envsubst '$NAMESPACE' < consumer-ca-pem.yaml | kubectl apply -n $NAMESPACE -f -
11 changes: 11 additions & 0 deletions tests/templates/kuttl/user-provided-tls/11-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 300
---
apiVersion: batch/v1
kind: Job
metadata:
name: tls-consumer-pkcs12-truststore
status:
succeeded: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: envsubst '$NAMESPACE' < consumer-pkcs12-truststore.yaml | kubectl apply -n $NAMESPACE -f -
Loading
Loading