mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-22 15:57:34 +00:00
306 lines
12 KiB
Go
306 lines
12 KiB
Go
|
package certificate
|
||
|
|
||
|
import (
|
||
|
"github.com/caos/orbos/mntr"
|
||
|
kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock"
|
||
|
"github.com/caos/orbos/pkg/labels"
|
||
|
"github.com/caos/orbos/pkg/tree"
|
||
|
"github.com/caos/zitadel/operator/database/kinds/databases/core"
|
||
|
coremock "github.com/caos/zitadel/operator/database/kinds/databases/core/mock"
|
||
|
"github.com/caos/zitadel/operator/database/kinds/databases/managed/certificate/pem"
|
||
|
"github.com/golang/mock/gomock"
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
corev1 "k8s.io/api/core/v1"
|
||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
caPem = `-----BEGIN CERTIFICATE-----
|
||
|
MIIE9TCCAt2gAwIBAgICB+MwDQYJKoZIhvcNAQELBQAwKzESMBAGA1UEChMJQ29j
|
||
|
a3JvYWNoMRUwEwYDVQQDEwxDb2Nrcm9hY2ggQ0EwHhcNMjAxMjAxMTAyMjA0WhcN
|
||
|
MzAxMjAxMTAyMjA0WjArMRIwEAYDVQQKEwlDb2Nrcm9hY2gxFTATBgNVBAMTDENv
|
||
|
Y2tyb2FjaCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOja5IXJ
|
||
|
GUY9sFgyvWkav+O74gzcv8y69uJzSOx0piOP+sfpZWVeGEjqO4JgdcS5NPMrT5Tb
|
||
|
aJ52CjiOdlHVTyR87i5JmOIvA2qA4dWQmSbX7AQ8r9ptYDe9xMn+qFegcbr4YxCz
|
||
|
K9mmbDZUhlLO7cz3QV6nvRxGFWbzffo8BXZnOUCAOyOHrbnPpLumnfZlL5BckdtY
|
||
|
pS7jAlUpKSMBTK4AHcmrouFsNKHqlUopYXeJFdg9g1F0DuCnVP9x7+XcUW8dAVut
|
||
|
Q7Jswy+++GAXs6mPVsYFLXUSYNyW+Bfl/jKwx0XTQx/6iyNpK0XtAzjBZFjXwmot
|
||
|
0mODkqnfE3BB4lXxZ5knomAQEGSScUhCUb9upbF4uJJF27xr/kIkwtWxMGpCXds0
|
||
|
IxI+wNRCenhfFZEIQCzri0zn6WdN8b/gbv1BErNcccYwolPUv1oUgYbzowbQ5O2D
|
||
|
aLQPqO1VAZiZHLxb787bRywpCl33VZ1ptMHi2ogKjcsh4DQ9SsRj+rU/Tk5lyk7G
|
||
|
FHteyHcq12TGpz9/CQYMacl8yeRRHfNO3Rq0jFTYeD4+ZdVBPKeuTHyXGzy2T157
|
||
|
pgqMFzwqxlNYPzpuz7xsZBExJzCtcomB8fMlsCJnxV/kuMTTsWsPrRc7hsqzBCq3
|
||
|
plfYT8a7EBCVmJmDu+6mMVh+A9M2zZCqtV57AgMBAAGjIzAhMA4GA1UdDwEB/wQE
|
||
|
AwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQDRmkBYDk/F
|
||
|
lYTgMaL7yhRAowDR8mtOl06Oba/MCDDsmBvfOVIqY9Sa9sJtb78Uvecv9WAE4qpb
|
||
|
PNSaIvNmujmGQrBxtGwQdeHZvtXQ1lKAGBM+ukfz/NFU+6rwOdTuLgS5jTaiM4r1
|
||
|
uMoIG6S5z/brWGHAw8Qv2Fq05dSLnevmPWK903V/RnwmCKT9as5Qpfkaie2PNory
|
||
|
euxVGeGolxzgbSps3ZJlDSSymQBl10iJYYdGIsgcw5FHcCdpS4AutdpQbIFuCGk2
|
||
|
CHTcTTa4KMaVfRm/gKm1gh8UnuVDLBKQS8+1CHFYUnih8ozBNUyBo5r5L4BHJK/n
|
||
|
f0gnrYqaxtqPAyHkfo0PRc50HlAQRS/gW8ESv2PQmcSWlDggEzXt5MqFIYOfEXWE
|
||
|
gtC7Ct1P7gzIRxolYVsNSgBR62sJM1PUa39E5v0QJsmuM51txHuw/PGqkkBlEwx9
|
||
|
4u3FFXD9Pslg/g1l50Ek5O3/TWMta4Q+NagDDaOdkb4LRQr522ySgGIinBw00Xr+
|
||
|
Ics2L42rP1LQyaE7+BljDEwmGaT7mrl8QGZR9uv/9mbtk2+q7wAOQzcMSFFACfwx
|
||
|
KdKENmK0GpQZ6HaeDZO7wxGiAyFKhTNpd39XNOEhaKpWLSUxnZTLGlMIzvSyMGCj
|
||
|
PV3xm+Xg1Xvki7f/qC1djysMcaokoJzNdg==
|
||
|
-----END CERTIFICATE-----
|
||
|
`
|
||
|
caPrivPem = `-----BEGIN RSA PRIVATE KEY-----
|
||
|
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
|
||
|
-----END RSA PRIVATE KEY-----
|
||
|
`
|
||
|
)
|
||
|
|
||
|
func TestCertificate_AdaptWithCA(t *testing.T) {
|
||
|
monitor := mntr.Monitor{}
|
||
|
namespace := "testNs"
|
||
|
clusterDns := "testDns"
|
||
|
componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "cockroachdb", "v0"), "cockroachdb")
|
||
|
|
||
|
nodeLabels := map[string]string{
|
||
|
"app.kubernetes.io/component": "cockroachdb",
|
||
|
"app.kubernetes.io/managed-by": "testOp",
|
||
|
"app.kubernetes.io/name": "cockroachdb.node",
|
||
|
"app.kubernetes.io/part-of": "testProd",
|
||
|
"orbos.ch/selectable": "yes",
|
||
|
}
|
||
|
dbCurrent := coremock.NewMockDatabaseCurrent(gomock.NewController(t))
|
||
|
k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t))
|
||
|
|
||
|
secretList := &corev1.SecretList{
|
||
|
Items: []corev1.Secret{},
|
||
|
}
|
||
|
ca, err := pem.DecodeCertificate([]byte(caPem))
|
||
|
assert.NoError(t, err)
|
||
|
caPriv, err := pem.DecodeKey([]byte(caPrivPem))
|
||
|
assert.NoError(t, err)
|
||
|
|
||
|
k8sClient.EXPECT().ListSecrets(namespace, nodeLabels).Times(1).Return(secretList, nil)
|
||
|
dbCurrent.EXPECT().GetCertificate().Times(1).Return(ca)
|
||
|
dbCurrent.EXPECT().GetCertificateKey().Times(1).Return(caPriv)
|
||
|
dbCurrent.EXPECT().SetCertificate(ca).Times(1)
|
||
|
dbCurrent.EXPECT().SetCertificateKey(caPriv).Times(1)
|
||
|
|
||
|
queried := map[string]interface{}{}
|
||
|
current := &tree.Tree{
|
||
|
Parsed: dbCurrent,
|
||
|
}
|
||
|
|
||
|
core.SetQueriedForDatabase(queried, current)
|
||
|
|
||
|
query, _, _, _, _, err := AdaptFunc(monitor, namespace, componentLabels, clusterDns, true)
|
||
|
assert.NoError(t, err)
|
||
|
|
||
|
ensure, err := query(k8sClient, queried)
|
||
|
assert.NoError(t, err)
|
||
|
assert.NotNil(t, ensure)
|
||
|
|
||
|
assert.NoError(t, ensure(k8sClient))
|
||
|
}
|
||
|
|
||
|
func TestNode_AdaptWithoutCA(t *testing.T) {
|
||
|
monitor := mntr.Monitor{}
|
||
|
namespace := "testNs"
|
||
|
clusterDns := "testDns"
|
||
|
componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "cockroachdb", "v0"), "cockroachdb")
|
||
|
|
||
|
nodeLabels := map[string]string{
|
||
|
"app.kubernetes.io/component": "cockroachdb",
|
||
|
"app.kubernetes.io/managed-by": "testOp",
|
||
|
"app.kubernetes.io/name": "cockroachdb.node",
|
||
|
"app.kubernetes.io/part-of": "testProd",
|
||
|
"orbos.ch/selectable": "yes",
|
||
|
}
|
||
|
dbCurrent := coremock.NewMockDatabaseCurrent(gomock.NewController(t))
|
||
|
k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t))
|
||
|
|
||
|
secretList := &corev1.SecretList{
|
||
|
Items: []corev1.Secret{},
|
||
|
}
|
||
|
|
||
|
k8sClient.EXPECT().ListSecrets(namespace, nodeLabels).Times(1).Return(secretList, nil)
|
||
|
dbCurrent.EXPECT().GetCertificate().Times(1).Return(nil)
|
||
|
dbCurrent.EXPECT().GetCertificateKey().Times(1).Return(nil)
|
||
|
dbCurrent.EXPECT().SetCertificate(gomock.Any()).Times(1)
|
||
|
dbCurrent.EXPECT().SetCertificateKey(gomock.Any()).Times(1)
|
||
|
k8sClient.EXPECT().ApplySecret(gomock.Any()).Times(1).Return(nil)
|
||
|
|
||
|
queried := map[string]interface{}{}
|
||
|
current := &tree.Tree{
|
||
|
Parsed: dbCurrent,
|
||
|
}
|
||
|
|
||
|
core.SetQueriedForDatabase(queried, current)
|
||
|
|
||
|
query, _, _, _, _, err := AdaptFunc(monitor, namespace, componentLabels, clusterDns, true)
|
||
|
assert.NoError(t, err)
|
||
|
|
||
|
ensure, err := query(k8sClient, queried)
|
||
|
assert.NoError(t, err)
|
||
|
assert.NotNil(t, ensure)
|
||
|
|
||
|
assert.NoError(t, ensure(k8sClient))
|
||
|
}
|
||
|
|
||
|
func TestNode_AdaptAlreadyExisting(t *testing.T) {
|
||
|
monitor := mntr.Monitor{}
|
||
|
namespace := "testNs"
|
||
|
clusterDns := "testDns"
|
||
|
componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "cockroachdb", "v0"), "cockroachdb")
|
||
|
|
||
|
nodeLabels := map[string]string{
|
||
|
"app.kubernetes.io/component": "cockroachdb",
|
||
|
"app.kubernetes.io/managed-by": "testOp",
|
||
|
"app.kubernetes.io/name": "cockroachdb.node",
|
||
|
"app.kubernetes.io/part-of": "testProd",
|
||
|
"orbos.ch/selectable": "yes",
|
||
|
}
|
||
|
dbCurrent := coremock.NewMockDatabaseCurrent(gomock.NewController(t))
|
||
|
k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t))
|
||
|
|
||
|
caCertKey := "ca.crt"
|
||
|
caPrivKeyKey := "ca.key"
|
||
|
|
||
|
secretList := &corev1.SecretList{
|
||
|
Items: []corev1.Secret{{
|
||
|
ObjectMeta: metav1.ObjectMeta{},
|
||
|
Data: map[string][]byte{
|
||
|
caCertKey: []byte(caPem),
|
||
|
caPrivKeyKey: []byte(caPrivPem),
|
||
|
},
|
||
|
Type: "Opaque",
|
||
|
}},
|
||
|
}
|
||
|
|
||
|
k8sClient.EXPECT().ListSecrets(namespace, nodeLabels).Times(1).Return(secretList, nil)
|
||
|
dbCurrent.EXPECT().SetCertificate(gomock.Any()).Times(1)
|
||
|
dbCurrent.EXPECT().SetCertificateKey(gomock.Any()).Times(1)
|
||
|
|
||
|
queried := map[string]interface{}{}
|
||
|
current := &tree.Tree{
|
||
|
Parsed: dbCurrent,
|
||
|
}
|
||
|
|
||
|
core.SetQueriedForDatabase(queried, current)
|
||
|
|
||
|
query, _, _, _, _, err := AdaptFunc(monitor, namespace, componentLabels, clusterDns, true)
|
||
|
assert.NoError(t, err)
|
||
|
|
||
|
ensure, err := query(k8sClient, queried)
|
||
|
assert.NoError(t, err)
|
||
|
assert.NotNil(t, ensure)
|
||
|
|
||
|
assert.NoError(t, ensure(k8sClient))
|
||
|
}
|
||
|
|
||
|
func TestNode_AdaptCreateUser(t *testing.T) {
|
||
|
monitor := mntr.Monitor{}
|
||
|
clusterDns := "testDns"
|
||
|
namespace := "testNs"
|
||
|
user := "test"
|
||
|
componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "cockroachdb", "v0"), "cockroachdb")
|
||
|
|
||
|
nodeLabels := map[string]string{
|
||
|
"app.kubernetes.io/component": "cockroachdb",
|
||
|
"app.kubernetes.io/managed-by": "testOp",
|
||
|
"app.kubernetes.io/name": "cockroachdb.node",
|
||
|
"app.kubernetes.io/part-of": "testProd",
|
||
|
"orbos.ch/selectable": "yes",
|
||
|
}
|
||
|
dbCurrent := coremock.NewMockDatabaseCurrent(gomock.NewController(t))
|
||
|
k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t))
|
||
|
|
||
|
ca, err := pem.DecodeCertificate([]byte(caPem))
|
||
|
assert.NoError(t, err)
|
||
|
caPriv, err := pem.DecodeKey([]byte(caPrivPem))
|
||
|
assert.NoError(t, err)
|
||
|
|
||
|
caCertKey := "ca.crt"
|
||
|
caPrivKeyKey := "ca.key"
|
||
|
|
||
|
secretList := &corev1.SecretList{
|
||
|
Items: []corev1.Secret{{
|
||
|
ObjectMeta: metav1.ObjectMeta{},
|
||
|
Data: map[string][]byte{
|
||
|
caCertKey: []byte(caPem),
|
||
|
caPrivKeyKey: []byte(caPrivPem),
|
||
|
},
|
||
|
Type: "Opaque",
|
||
|
}},
|
||
|
}
|
||
|
|
||
|
k8sClient.EXPECT().ListSecrets(namespace, nodeLabels).Times(1).Return(secretList, nil)
|
||
|
|
||
|
dbCurrent.EXPECT().GetCertificate().Times(1).Return(ca)
|
||
|
dbCurrent.EXPECT().GetCertificateKey().Times(1).Return(caPriv)
|
||
|
dbCurrent.EXPECT().SetCertificate(gomock.Any()).Times(1)
|
||
|
dbCurrent.EXPECT().SetCertificateKey(gomock.Any()).Times(1)
|
||
|
k8sClient.EXPECT().ApplySecret(gomock.Any())
|
||
|
|
||
|
queried := map[string]interface{}{}
|
||
|
current := &tree.Tree{
|
||
|
Parsed: dbCurrent,
|
||
|
}
|
||
|
core.SetQueriedForDatabase(queried, current)
|
||
|
|
||
|
_, _, createUser, _, _, err := AdaptFunc(monitor, namespace, componentLabels, clusterDns, true)
|
||
|
assert.NoError(t, err)
|
||
|
query, err := createUser(user)
|
||
|
assert.NoError(t, err)
|
||
|
|
||
|
ensure, err := query(k8sClient, queried)
|
||
|
assert.NoError(t, err)
|
||
|
assert.NotNil(t, ensure)
|
||
|
|
||
|
assert.NoError(t, ensure(k8sClient))
|
||
|
}
|