-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
up: upgrade base docker image; add envtest integration tests (#85)
- Loading branch information
Showing
17 changed files
with
367 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
apiVersion: isindir.github.com/v1alpha3 | ||
kind: SopsSecret | ||
metadata: | ||
name: test-sopssecret | ||
namespace: default | ||
spec: | ||
secretTemplates: | ||
- name: test-stringdata-token | ||
stringData: | ||
token: Wb4ziZdELkdUf6m6KtNd7iRjjQRvSeJno5meH4NAGHFmpqJyEsekZ2WjX232s4Gj | ||
- name: test-data-token | ||
data: | ||
token: V2I0emlaZEVMa2RVZjZtNkt0TmQ3aVJqalFSdlNlSm5vNW1lSDROQUdIRm1wcUp5RXNla1oyV2pYMjMyczRHag== | ||
- name: test-labels-annotations-jenkins-secret | ||
labels: | ||
"jenkins.io/credentials-type": "usernamePassword" | ||
annotations: | ||
"jenkins.io/credentials-description" : "credentials from Kubernetes" | ||
stringData: | ||
username: myUsername | ||
password: 'Pa$$word' | ||
- name: test-type-docker-login | ||
type: 'kubernetes.io/dockerconfigjson' | ||
stringData: | ||
.dockerconfigjson: '{"auths":{"index.docker.io":{"username":"imyuser","password":"mypass","email":"[email protected]","auth":"aW15dXNlcjpteXBhc3M="}}}' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
apiVersion: isindir.github.com/v1alpha3 | ||
kind: SopsSecret | ||
metadata: | ||
name: test-sopssecret | ||
namespace: default | ||
spec: | ||
secretTemplates: | ||
- name: ENC[AES256_GCM,data:6V4Ucx7n6A11VkrZtCiyqUSeKKFC,iv:5E1Xu6eFqkE4kM2q7Yf9dtoc8399uyEhfnj2Ni9BUc0=,tag:J8NkiHxnG6stFZkGF090gA==,type:str] | ||
stringData: | ||
token: ENC[AES256_GCM,data:A5Q72PY++0z7uKfIX2jSHHcOBoLj3MltCnPPl6v74MmflcqmZRCC3fR1EdzaaOAj1ILKJHBMMKf73eLo/W+Cmw==,iv:/xpIAjjX05PmdPznshlO0vsHR3irXHhDV6YdjL6n6w4=,tag:tDfGF+NVVnoYGw78N1/UAg==,type:str] | ||
- name: ENC[AES256_GCM,data:pCSWLt3EBykhIClt9t8W,iv:CdzcJzAZFIpnvcUcQQyHAuIdYcp2S3ufwrGiWKyOCFo=,tag:xB6jysJ1LcI1kpvwuBpOoQ==,type:str] | ||
data: | ||
token: ENC[AES256_GCM,data:1eRxH3SpEsvL/LCgV0uTdbZUzq1aoTa2/urzJKf/CStET4nbCpqDR8VIvl4sb7Ym4UdblKggAd0IxcVCuQEnpdnLs0fhRi0aaVqyJBKjD4ewmFamNpBWEA==,iv:tgR7wSjxezstm+e1WuMLlZ6Gs6zVkfo6yDavOUZV4OA=,tag:STLqjwHQqXcQ/xPWrV9Skg==,type:str] | ||
- name: ENC[AES256_GCM,data:YPpvKUryfv2HRzeSaPV0WfBG3Ob4Ag26Lvy4CmylMA5wPkKqaZQ=,iv:PCn6Zp+iEsF+CSK7An+VkXhg1JD3TJ+nE8gVeKTg2T0=,tag:MuLpy+KxHWCevJUxq/tFbg==,type:str] | ||
labels: | ||
jenkins.io/credentials-type: ENC[AES256_GCM,data:Wrqn2XG5KjUKOzzBcRrJTQ==,iv:NEm+ZM5KBK+eF/eWgdNcT1190eIjOEaGTNamVfveXLY=,tag:DejUX7y+CC2V7qQZbN5GNw==,type:str] | ||
annotations: | ||
jenkins.io/credentials-description: ENC[AES256_GCM,data:6DxJ5dSqKPd5cTlVc2h+cvcdCYxVXnHvKIp8,iv:KeBAk4B8je2qKxV5xPMU+5i9v3UI3bIeY1NdhvSyRPg=,tag:Cw/rPrYy/PRcdUcMzUNYQQ==,type:str] | ||
stringData: | ||
username: ENC[AES256_GCM,data:2331v9GLgGmspQ==,iv:3gOdC9ICqE/IGOoTESCpOBb6Z+MV4pJ/e1T/WulLPtg=,tag:OQILlBVUoBNodkhvrI5IlQ==,type:str] | ||
password: ENC[AES256_GCM,data:YKZtVH5w5uRNTds=,iv:mK/us3zPUtKa1nUv+Lw8A9DZHvuoHsX5i3i0G/9XJLc=,tag:+HMWTSQeYD9HK3fYldzeGw==,type:str] | ||
- name: ENC[AES256_GCM,data:AdqTEEJdkr61Lr6Rgc7n/lh7vwoclA==,iv:8ROnJOl78gE9i2TBKyhAa4RhnQmNnIBgNjlupJlrhCA=,tag:OMYJjY+MmXH/9AYnF7uJqg==,type:str] | ||
type: ENC[AES256_GCM,data:rLjSr2aByTeACO2ucCj6h81qdS9QNmLs2QTB4wjJ,iv:KBmpgMCaK79uVdAsVxZMRqe1CQGDXxPESvwKtSPh6+s=,tag:s/4f6MnEIDoj1doDYUjaHQ==,type:str] | ||
stringData: | ||
.dockerconfigjson: ENC[AES256_GCM,data:EBB6l/PQVfEMCg6MYe1yUwGV8RxPyAUMom7DvtTDdce8lY1wztEWyrmCHPLXE/IkIq3/Iz6QTyyMFFBUERJovz5aYSwBAMeX6ocle9SG3wMWe1/cySYIQednL+PF1GWNUaIn1MEMO7PP1VopEuZSdWtHvXxfrubWC2mRMmhHaw==,iv:HV/C0ceSQcFveWzXBVZMfGSHV/bRBeB7ka/zxrHnrY8=,tag:HILN9fQBDbWFxjjnkBkp4Q==,type:str] | ||
sops: | ||
kms: [] | ||
gcp_kms: [] | ||
azure_kv: [] | ||
hc_vault: [] | ||
age: | ||
- recipient: age1pnmp2nq5qx9z4lpmachyn2ld07xjumn98hpeq77e4glddu96zvms9nn7c8 | ||
enc: | | ||
-----BEGIN AGE ENCRYPTED FILE----- | ||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoNUpVbVhNbWluZjFyRHhT | ||
OWoxYU9oU1h6dFYycGVMb2RJTlhWMFhPTVFnCkQxb3liRG9TS096TFN4UVJFK25Y | ||
K2x5SG53dmM4ZHF2dDZWdXdDVHN3Yk0KLS0tIE1xTlN1Unk4aURZWFNoNUhGMGc3 | ||
YzlyY0NwQnptejk2RWpRV3RMUDVRWm8KDsF8k67qcYafOPIiAYVeQ+SvzLobq0pg | ||
h8OmBkNaahywzLTAjEcy8j84JRa1muAEJEX4fCLzE+7hsN+11Yc2gA== | ||
-----END AGE ENCRYPTED FILE----- | ||
lastmodified: "2021-09-05T19:36:03Z" | ||
mac: ENC[AES256_GCM,data:9K8gQB0RJXuVFeEzNg8Kuo++50xvdk8NR8Y0yIJTcjdcAAI+V733yRBBCLt8AzIERifUqI2geZcdKJeOq5mQ5Bg5WA5bqBowBXOmT9Oxmg7M0uUIbfoIV7X9hG42rTcZ+gBd8d3YFTAY4waFlgY7sTuJvacDt+cHJkh0a1+CGPY=,iv:F3DHuCUDrLpAHktYy2x5qkYbQf1gs0t8tFLv61YrEiU=,tag:Xdi7t78Z44T2j041CaCR8A==,type:str] | ||
pgp: [] | ||
encrypted_suffix: Templates | ||
version: 3.7.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# created: 2021-08-20T15:53:30+01:00 | ||
# public key: age1pnmp2nq5qx9z4lpmachyn2ld07xjumn98hpeq77e4glddu96zvms9nn7c8 | ||
AGE-SECRET-KEY-1CQ3KTYJ25YDYA2XVYFGH8P5UJWCENLJ02ZRHMH9YV84WKQVGP3SS07GYNK |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package controllers_test | ||
|
||
import ( | ||
"os" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
|
||
isindirv1alpha3 "github.com/isindir/sops-secrets-operator/api/v1alpha3" | ||
controller "github.com/isindir/sops-secrets-operator/controllers" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes/scheme" | ||
|
||
"context" | ||
"io/ioutil" | ||
"path/filepath" | ||
"time" | ||
) | ||
|
||
var _ = Describe("SopssecretController", func() { | ||
TestSecretObject00 := &isindirv1alpha3.SopsSecret{} | ||
BeforeEach(func() { | ||
content, err := ioutil.ReadFile(filepath.Join("..", "config", "age-test-key", "00-test-secrets.yaml")) | ||
Expect(err).Should(BeNil()) | ||
|
||
obj, _, err := scheme.Codecs.UniversalDeserializer().Decode(content, nil, nil) | ||
TestSecretObject00 = obj.(*isindirv1alpha3.SopsSecret) | ||
Expect(err).Should(BeNil()) | ||
}) | ||
|
||
// Define utility constants for object names and testing timeouts/durations and intervals. | ||
const ( | ||
SopsSecretName = "test-sops-secret" | ||
SopsSecretNamespace = "default" | ||
|
||
timeout = time.Second * 10 | ||
duration = time.Second * 10 | ||
interval = time.Millisecond * 250 | ||
) | ||
|
||
// This is to ensure test environment is configured correctly | ||
Context("When Running controller reconciler", func() { | ||
It("It should have SOPS env variables defined", func() { | ||
// Key env variable must be set correctly | ||
Expect(os.Getenv("SOPS_AGE_RECIPIENTS")).To(Equal("age1pnmp2nq5qx9z4lpmachyn2ld07xjumn98hpeq77e4glddu96zvms9nn7c8")) | ||
|
||
// File containing private key must exist | ||
ageKeyFileName := os.Getenv("SOPS_AGE_KEY_FILE") | ||
_, err := os.Stat(ageKeyFileName) | ||
Expect(err).To(BeNil()) | ||
}, float64(timeout)) | ||
}) | ||
|
||
Context("When Creating Malformed SopsSecret Object", func() { | ||
It("Should Fail to Create SopsSecret", func() { | ||
By("By creating a new SopsSecret") | ||
ctx := context.Background() | ||
sopsSecret := &isindirv1alpha3.SopsSecret{ | ||
TypeMeta: metav1.TypeMeta{ | ||
APIVersion: "github.com/isindir/sops-secrets-operator/api/v1alpha3", | ||
Kind: "SopsSecret", | ||
}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: SopsSecretName, | ||
Namespace: SopsSecretNamespace, | ||
}, | ||
Spec: isindirv1alpha3.SopsSecretSpec{ | ||
Suspend: true, | ||
SecretsTemplate: []isindirv1alpha3.SopsSecretTemplate{}, | ||
}, | ||
} | ||
Expect(controller.K8sClient.Create(ctx, sopsSecret)).NotTo(Succeed()) | ||
}, float64(timeout)) | ||
}) | ||
|
||
Context("When Creating Correctly Defined SopsSecret Object", func() { | ||
It("Should Succeed to Create SopsSecret", func() { | ||
By("By creating a new SopsSecret version 00") | ||
ctx := context.Background() | ||
|
||
Expect(controller.K8sClient.Create(ctx, TestSecretObject00)).To(Succeed()) | ||
time.Sleep(10 * time.Second) | ||
|
||
By("By checking that correct number of secrets was created") | ||
listCommandOptions := &client.ListOptions{Namespace: "default"} | ||
secretsList := &corev1.SecretList{} | ||
Expect(controller.K8sClient.List(ctx, secretsList, listCommandOptions)).To(Succeed()) | ||
// 4 from SopsSecret object + 1 for Service Account | ||
Expect(len(secretsList.Items)).To(Equal(4)) | ||
|
||
By("By checking content of token stringdata test secret") | ||
testSecret := &corev1.Secret{} | ||
tagrgetSecretNamespacedName := &types.NamespacedName{Namespace: "default", Name: "test-stringdata-token"} | ||
Expect(controller.K8sClient.Get(ctx, *tagrgetSecretNamespacedName, testSecret)).To(Succeed()) | ||
Expect(string(testSecret.Data["token"])).To(Equal("Wb4ziZdELkdUf6m6KtNd7iRjjQRvSeJno5meH4NAGHFmpqJyEsekZ2WjX232s4Gj")) | ||
|
||
By("By checking content of token data test secret") | ||
tagrgetSecretNamespacedName = &types.NamespacedName{Namespace: "default", Name: "test-data-token"} | ||
Expect(controller.K8sClient.Get(ctx, *tagrgetSecretNamespacedName, testSecret)).To(Succeed()) | ||
Expect(string(testSecret.Data["token"])).To(Equal("Wb4ziZdELkdUf6m6KtNd7iRjjQRvSeJno5meH4NAGHFmpqJyEsekZ2WjX232s4Gj")) | ||
|
||
By("By checking docker secret type") | ||
tagrgetSecretNamespacedName = &types.NamespacedName{Namespace: "default", Name: "test-type-docker-login"} | ||
Expect(controller.K8sClient.Get(ctx, *tagrgetSecretNamespacedName, testSecret)).To(Succeed()) | ||
Expect(testSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) | ||
|
||
By("By checking jenkins test secret contains 1 label and 1 annotation") | ||
tagrgetSecretNamespacedName = &types.NamespacedName{Namespace: "default", Name: "test-labels-annotations-jenkins-secret"} | ||
Expect(controller.K8sClient.Get(ctx, *tagrgetSecretNamespacedName, testSecret)).To(Succeed()) | ||
Expect(string(testSecret.Data["username"])).To(Equal("myUsername")) | ||
Expect(string(testSecret.Data["password"])).To(Equal("Pa58163word")) | ||
Expect(testSecret.Labels["jenkins.io/credentials-type"]).To(Equal("usernamePassword")) | ||
Expect(testSecret.Annotations["jenkins.io/credentials-description"]).To(Equal("credentials from Kubernetes")) | ||
|
||
By("By updating a managed k8s secret value outside of SopsSecret object") | ||
testSecret.Data["username"] = []byte("newUsername") | ||
Expect(controller.K8sClient.Update(ctx, testSecret)).To(Succeed()) | ||
time.Sleep(10 * time.Second) | ||
Expect(controller.K8sClient.Get(ctx, *tagrgetSecretNamespacedName, testSecret)).To(Succeed()) | ||
Expect(string(testSecret.Data["username"])).To(Equal("myUsername")) | ||
|
||
By("By deleting data item from a managed k8s secret value outside of SopsSecret object") | ||
delete(testSecret.Data, "username") | ||
Expect(controller.K8sClient.Update(ctx, testSecret)).To(Succeed()) | ||
time.Sleep(10 * time.Second) | ||
Expect(controller.K8sClient.Get(ctx, *tagrgetSecretNamespacedName, testSecret)).To(Succeed()) | ||
Expect(string(testSecret.Data["username"])).To(Equal("myUsername")) | ||
|
||
By("By checking that status of the SopsSecret is Healthy") | ||
sourceSopsSecret := &isindirv1alpha3.SopsSecret{} | ||
sourceSopsSecretNamespacedName := &types.NamespacedName{Namespace: "default", Name: "test-sopssecret"} | ||
Expect(controller.K8sClient.Get(ctx, *sourceSopsSecretNamespacedName, sourceSopsSecret)).To(Succeed()) | ||
Expect(sourceSopsSecret.Status.Message).To(Equal("Healthy")) | ||
|
||
By("By removing secret template from SopsSecret must remove managed k8s secret") | ||
// Delete template from SopsSecret and update | ||
// Delete target secret (envtest will not perform garbage collection) | ||
copy(sourceSopsSecret.Spec.SecretsTemplate[0:], sourceSopsSecret.Spec.SecretsTemplate[1:]) | ||
sourceSopsSecret.Spec.SecretsTemplate = sourceSopsSecret.Spec.SecretsTemplate[:len(sourceSopsSecret.Spec.SecretsTemplate)-1] | ||
Expect(controller.K8sClient.Update(ctx, sourceSopsSecret)).To(Succeed()) | ||
testSecret = &corev1.Secret{} | ||
tagrgetSecretNamespacedName = &types.NamespacedName{Namespace: "default", Name: "test-stringdata-token"} | ||
Expect(controller.K8sClient.Get(ctx, *tagrgetSecretNamespacedName, testSecret)).To(Succeed()) | ||
Expect(controller.K8sClient.Delete(ctx, testSecret)).To(Succeed()) | ||
time.Sleep(10 * time.Second) | ||
secretsList = &corev1.SecretList{} | ||
Expect(controller.K8sClient.List(ctx, secretsList, listCommandOptions)).To(Succeed()) | ||
// 3 from SopsSecret object + 1 for Service Account | ||
Expect(len(secretsList.Items)).To(Equal(3)) | ||
Expect(controller.K8sClient.Get(ctx, *sourceSopsSecretNamespacedName, sourceSopsSecret)).To(Succeed()) | ||
Expect(sourceSopsSecret.Status.Message).To(Equal("Healthy")) | ||
}, float64(timeout)) | ||
}) | ||
|
||
// TODO: check by creating sops secret with one broken k8s secret definition will manifest in non-healthy sops object | ||
// TODO: check pre-existing secret conflict with SopsSecret template | ||
// TODO: check pre-existing k8s secret being taken over by SopsSecret using sops managed annotation | ||
}) |
Oops, something went wrong.