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

Gardener config credential repository #55

Merged
merged 32 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
786edce
add dev docs diagrams
jschicktanz Jul 8, 2022
0cb6e36
implement first version of secret server credentials repo
jschicktanz Jul 13, 2022
f710aee
fix typo
jschicktanz Jul 13, 2022
302ffbb
add pointer receivers to credential repos
jschicktanz Jul 13, 2022
8ab9366
v2 implementation
jschicktanz Jul 29, 2022
938cfb6
finish first working version
jschicktanz Aug 1, 2022
4e86cc0
rework
jschicktanz Aug 2, 2022
dcae60d
simplify code
jschicktanz Aug 2, 2022
734c8c5
rework
jschicktanz Aug 3, 2022
bd82787
only add scheme and port to consumer identity if not empty
jschicktanz Aug 8, 2022
d438e8e
refactoring
jschicktanz Aug 9, 2022
314dcd9
fix import cycle
jschicktanz Aug 10, 2022
d42f6ad
several bugfixes
jschicktanz Aug 10, 2022
b41d116
bugfixes
jschicktanz Aug 11, 2022
19afc32
Merge branch 'main' into js-work
jschicktanz Aug 11, 2022
651e0b1
fix compile errors
jschicktanz Aug 11, 2022
58870c0
run go mod tidy
jschicktanz Aug 11, 2022
71649a2
review feedback
jschicktanz Aug 12, 2022
df967b8
Review feedback
jschicktanz Aug 12, 2022
7dba5bc
fix indent
jschicktanz Aug 12, 2022
71baf49
trim leading slashes when creating consumer identities
jschicktanz Aug 12, 2022
3c08c1e
review feedback
jschicktanz Aug 12, 2022
1521565
read encryption key from context
jschicktanz Aug 18, 2022
93d2bc8
add missing code
jschicktanz Aug 18, 2022
94d51b9
Merge branch 'main' into js-work
jschicktanz Aug 18, 2022
5c916d8
make format
jschicktanz Aug 18, 2022
50a0c94
review feedback
jschicktanz Aug 22, 2022
52eaa24
small refactoring
jschicktanz Aug 23, 2022
016112e
Merge branch 'main' into js-work
Skarlso Aug 26, 2022
b8b933a
review feedback
jschicktanz Aug 31, 2022
9e16811
allow retry of read operation if secret server is unavailable
jschicktanz Aug 31, 2022
c877f6e
review feedback
jschicktanz Sep 2, 2022
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
71 changes: 47 additions & 24 deletions pkg/contexts/credentials/repositories/gardenerconfig/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,11 @@ import (
local "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/gardenerconfig"
gardenercfgcpi "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/gardenerconfig/cpi"
"github.com/open-component-model/ocm/pkg/contexts/datacontext/attrs/vfsattr"
"github.com/open-component-model/ocm/pkg/contexts/oci/identity"
)

var _ = Describe("gardener config", func() {
props := common.Properties{
"username": "abc",
"password": "123",
}

creds := `{
containerRegistryCfg := `{
"container_registry": {
"test-credentials": {
"username": "abc",
Expand All @@ -42,9 +38,20 @@ var _ = Describe("gardener config", func() {
}
}`
encryptionKey := "abcdefghijklmnop"
encryptedCredentials := "Uz4mfePXFOUbjUEZnRrnG8zP2T7lRH6bR2rFHYgWDwZUXfW7D5wArwY4dsBACPVFNapF7kcM9z79+LvJXd2kNoIfvUyMOhrSDAyv4LtUqYSKBOoRH/aJMnXjmN9GQBCXSRSJs/Fu21AoDNo8fA9zYvvc7WxTldkYC/vHxLVNJu5j176e1QiaS9hwDjgNhgyUT3XUjHUyQ19PcRgwDglRLfiL4Cs/fYPPxdg4YZQdCnc="
encryptedContainerRegistryCfg := "Uz4mfePXFOUbjUEZnRrnG8zP2T7lRH6bR2rFHYgWDwZUXfW7D5wArwY4dsBACPVFNapF7kcM9z79+LvJXd2kNoIfvUyMOhrSDAyv4LtUqYSKBOoRH/aJMnXjmN9GQBCXSRSJs/Fu21AoDNo8fA9zYvvc7WxTldkYC/vHxLVNJu5j176e1QiaS9hwDjgNhgyUT3XUjHUyQ19PcRgwDglRLfiL4Cs/fYPPxdg4YZQdCnc="

specTemplate := `{"type":"GardenerConfig","url":"%s","configType":"container_registry","cipher":"%s","propagateConsumerIdentity":true}`
expectedConsumerId := cpi.ConsumerIdentity{
cpi.CONSUMER_ATTR_TYPE: identity.CONSUMER_TYPE,
hostpath.ID_HOSTNAME: "eu.gcr.io",
hostpath.ID_PATHPREFIX: "test-project",
}

expectedCreds := cpi.NewCredentials(common.Properties{
cpi.ATTR_USERNAME: "abc",
cpi.ATTR_PASSWORD: "123",
})

repoSpecTemplate := `{"type":"GardenerConfig","url":"%s","configType":"container_registry","cipher":"%s","propagateConsumerIdentity":true}`

var defaultContext credentials.Context

Expand All @@ -57,7 +64,7 @@ var _ = Describe("gardener config", func() {
url = "http://localhost:8080/container_registry"
cipher = local.Plaintext
)
expectedSpec := fmt.Sprintf(specTemplate, url, cipher)
expectedSpec := fmt.Sprintf(repoSpecTemplate, url, cipher)

spec := local.NewRepositorySpec("http://localhost:8080/container_registry", "container_registry", local.Plaintext, true)
data, err := json.Marshal(spec)
Expand All @@ -70,7 +77,7 @@ var _ = Describe("gardener config", func() {
url = "http://localhost:8080/container_registry"
cipher = local.Plaintext
)
specdata := fmt.Sprintf(specTemplate, url, cipher)
specdata := fmt.Sprintf(repoSpecTemplate, url, cipher)

spec, err := defaultContext.RepositorySpecForConfig([]byte(specdata), nil)
Expect(err).ToNot(HaveOccurred())
Expand All @@ -85,12 +92,12 @@ var _ = Describe("gardener config", func() {
It("resolves repository", func() {
svr := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(200)
_, err := writer.Write([]byte(creds))
_, err := writer.Write([]byte(containerRegistryCfg))
Expect(err).ToNot(HaveOccurred())
}))
defer svr.Close()

specdata := fmt.Sprintf(specTemplate, svr.URL, local.Plaintext)
specdata := fmt.Sprintf(repoSpecTemplate, svr.URL, local.Plaintext)

repo, err := defaultContext.RepositoryForConfig([]byte(specdata), nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to instantiate the repository, if the server is currently not available?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Expect(err).ToNot(HaveOccurred())
Expand All @@ -101,26 +108,32 @@ var _ = Describe("gardener config", func() {
It("retrieves credentials from unencrypted server", func() {
svr := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(200)
_, err := writer.Write([]byte(creds))
_, err := writer.Write([]byte(containerRegistryCfg))
Expect(err).ToNot(HaveOccurred())
}))
defer svr.Close()

spec := fmt.Sprintf(specTemplate, svr.URL, local.Plaintext)
spec := fmt.Sprintf(repoSpecTemplate, svr.URL, local.Plaintext)

repo, err := defaultContext.RepositoryForConfig([]byte(spec), nil)
Expect(err).ToNot(HaveOccurred())
Expect(repo).ToNot(BeNil())

credentials, err := repo.LookupCredentials("test-credentials")
credentialsFromRepo, err := repo.LookupCredentials("test-credentials")
Expect(err).ToNot(HaveOccurred())
Expect(credentials.Properties()).To(Equal(props))
Expect(credentialsFromRepo).To(Equal(expectedCreds))

credSrc, err := defaultContext.GetCredentialsForConsumer(expectedConsumerId, hostpath.IdentityMatcher(identity.CONSUMER_TYPE))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should use your identity matcher object provided by the package

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should bundle the consumer test in a dedicated test with the focus of testing the consumer propagation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Expect(err).ToNot(HaveOccurred())
credentialsFromCtx, err := credSrc.Credentials(defaultContext)
Expect(err).ToNot(HaveOccurred())
Expect(credentialsFromCtx).To(Equal(expectedCreds))
})

It("retrieves credentials from encrypted server", func() {
svr := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(200)
data, err := base64.StdEncoding.DecodeString(encryptedCredentials)
data, err := base64.StdEncoding.DecodeString(encryptedContainerRegistryCfg)
Expect(err).ToNot(HaveOccurred())
_, err = writer.Write(data)
Expect(err).ToNot(HaveOccurred())
Expand All @@ -144,16 +157,21 @@ var _ = Describe("gardener config", func() {

defaultContext.SetCredentialsForConsumer(id, creds)

spec := fmt.Sprintf(specTemplate, svr.URL, local.AESECB)
spec := fmt.Sprintf(repoSpecTemplate, svr.URL, local.AESECB)

repo, err := defaultContext.RepositoryForConfig([]byte(spec), nil)
Expect(err).ToNot(HaveOccurred())
Expect(repo).ToNot(BeNil())

credentials, err := repo.LookupCredentials("test-credentials")
credentialsFromRepo, err := repo.LookupCredentials("test-credentials")
Expect(err).ToNot(HaveOccurred())
Expect(credentialsFromRepo).To(Equal(expectedCreds))

Expect(credentials.Properties()).To(Equal(props))
credSrc, err := defaultContext.GetCredentialsForConsumer(expectedConsumerId, hostpath.IdentityMatcher(identity.CONSUMER_TYPE))
Expect(err).ToNot(HaveOccurred())
credentialsFromCtx, err := credSrc.Credentials(defaultContext)
Expect(err).ToNot(HaveOccurred())
Expect(credentialsFromCtx).To(Equal(expectedCreds))
})

It("retrieves credentials from file", func() {
Expand All @@ -164,22 +182,27 @@ var _ = Describe("gardener config", func() {
file, err := fs.Create(filename)
Expect(err).ToNot(HaveOccurred())

_, err = file.Write([]byte(creds))
_, err = file.Write([]byte(containerRegistryCfg))
Expect(err).ToNot(HaveOccurred())

err = file.Close()
Expect(err).ToNot(HaveOccurred())

spec := fmt.Sprintf(specTemplate, "file://"+filename, local.Plaintext)
spec := fmt.Sprintf(repoSpecTemplate, "file://"+filename, local.Plaintext)

repo, err := defaultContext.RepositoryForConfig([]byte(spec), nil)
Expect(err).ToNot(HaveOccurred())
Expect(repo).ToNot(BeNil())

credentials, err := repo.LookupCredentials("test-credentials")
credentialsFromRepo, err := repo.LookupCredentials("test-credentials")
Expect(err).ToNot(HaveOccurred())
Expect(credentialsFromRepo).To(Equal(expectedCreds))

Expect(credentials.Properties()).To(Equal(props))
credSrc, err := defaultContext.GetCredentialsForConsumer(expectedConsumerId, hostpath.IdentityMatcher(identity.CONSUMER_TYPE))
Expect(err).ToNot(HaveOccurred())
credentialsFromCtx, err := credSrc.Credentials(defaultContext)
Expect(err).ToNot(HaveOccurred())
Expect(credentialsFromCtx).To(Equal(expectedCreds))
})

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should test whether the provided credentials are properly propagated to their consumer ids.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

})
15 changes: 13 additions & 2 deletions pkg/contexts/credentials/repositories/gardenerconfig/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,23 @@ import (
const (
RepositoryType = "GardenerConfig"
RepositoryTypeV1 = RepositoryType + runtime.VersionSeparator + "v1"
CONSUMER_TYPE = "gardenerConfig"
CONSUMER_TYPE = "Config.gardener.cloud"
)

var identityMatcher = hostpath.IdentityMatcher(CONSUMER_TYPE)

func IdentityMatcher(pattern, cur, id cpi.ConsumerIdentity) bool {
return identityMatcher(pattern, cur, id)
}

func init() {
cpi.RegisterRepositoryType(RepositoryType, cpi.NewRepositoryType(RepositoryType, &RepositorySpec{}))
cpi.RegisterRepositoryType(RepositoryTypeV1, cpi.NewRepositoryType(RepositoryTypeV1, &RepositorySpec{}))

cpi.RegisterStandardIdentityMatcher(CONSUMER_TYPE, IdentityMatcher, `Gardener config credential matcher

It matches the <code>`+CONSUMER_TYPE+`</code> consumer type and additionally acts like
the <code>`+hostpath.IDENTITY_TYPE+`</code> type.`)
}

// RepositorySpec describes a secret server based credential repository interface.
Expand Down Expand Up @@ -73,7 +84,7 @@ func getKey(cctx cpi.Context, configURL string) ([]byte, error) {
id.SetNonEmptyValue(hostpath.ID_PORT, parsedURL.Port())

var creds cpi.Credentials
src, err := cctx.GetCredentialsForConsumer(id, hostpath.IdentityMatcher(CONSUMER_TYPE))
src, err := cctx.GetCredentialsForConsumer(id, identityMatcher)
if err != nil {
if !errors.IsErrUnknown(err) {
return nil, fmt.Errorf("unable to get credentials source: %w", err)
Expand Down