Skip to content

Commit

Permalink
feat: add credentials to authenticate to private repository/oci regis…
Browse files Browse the repository at this point in the history
…try (#32)
  • Loading branch information
matteogastaldello authored May 23, 2024
1 parent d7e0727 commit e55bfd5
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 20 deletions.
9 changes: 9 additions & 0 deletions apis/compositiondefinitions/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ type CompositionDefinitionList struct {
Items []CompositionDefinition `json:"items"`
}

type Credentials struct {
Username string `json:"username"`
PasswordRef rtv1.SecretKeySelector `json:"passwordRef"`
}

// +kubebuilder:validation:XValidation:rule="!has(oldSelf.version) || has(self.version)", message="Version is required once set"
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.repo) || has(self.repo)", message="Repo is required once set"
type ChartInfo struct {
Expand All @@ -30,6 +35,10 @@ type ChartInfo struct {
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Repo is immutable"
// +kubebuilder:validation:MaxLength=256
Repo string `json:"repo,omitempty"`

// Credentials: credentials for private repos
// +optional
Credentials *Credentials `json:"credentials,omitempty"`
}

type CompositionDefinitionSpec struct {
Expand Down
23 changes: 22 additions & 1 deletion apis/compositiondefinitions/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions crds/core.krateo.io_compositiondefinitions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,33 @@ spec:
properties:
chart:
properties:
credentials:
description: 'Credentials: credentials for private repos'
properties:
passwordRef:
description: A SecretKeySelector is a reference to a secret
key in an arbitrary namespace.
properties:
key:
description: The key to select.
type: string
name:
description: Name of the referenced object.
type: string
namespace:
description: Namespace of the referenced object.
type: string
required:
- key
- name
- namespace
type: object
username:
type: string
required:
- passwordRef
- username
type: object
repo:
description: 'Repo: helm repo name (for helm repo urls only)'
maxLength: 256
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (e *external) Observe(ctx context.Context, mg resource.Managed) (reconciler
return reconciler.ExternalObservation{}, errors.New(errNotCR)
}

pkg, err := chartfs.ForSpec(cr.Spec.Chart)
pkg, err := chartfs.ForSpec(ctx, e.kube, cr.Spec.Chart)
if err != nil {
return reconciler.ExternalObservation{}, err
}
Expand Down Expand Up @@ -221,7 +221,7 @@ func (e *external) Create(ctx context.Context, mg resource.Managed) error {
return nil
}

pkg, dir, err := generator.ChartInfoFromSpec(ctx, cr.Spec.Chart)
pkg, dir, err := generator.ChartInfoFromSpec(ctx, e.kube, cr.Spec.Chart)
if err != nil {
return err
}
Expand Down Expand Up @@ -299,7 +299,7 @@ func (e *external) Create(ctx context.Context, mg resource.Managed) error {
opts.Log = e.log.Debug
}

err, rbacErr := tools.Deploy(ctx, opts)
err, rbacErr := tools.Deploy(ctx, e.kube, opts)
if rbacErr != nil {
strErr := rbacErr.Error()
cr.Status.Error = &strErr
Expand Down Expand Up @@ -340,7 +340,7 @@ func (e *external) Delete(ctx context.Context, mg resource.Managed) error {
return nil
}

pkg, dir, err := generator.ChartInfoFromSpec(ctx, cr.Spec.Chart)
pkg, dir, err := generator.ChartInfoFromSpec(ctx, e.kube, cr.Spec.Chart)
if err != nil {
return err
}
Expand Down
20 changes: 16 additions & 4 deletions internal/controllers/compositiondefinitions/generator/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,37 @@ import (
"github.com/krateoplatformops/core-provider/internal/helm/getter"
"github.com/krateoplatformops/core-provider/internal/strutil"
"github.com/krateoplatformops/core-provider/internal/tgzfs"
"github.com/krateoplatformops/core-provider/internal/tools/resolvers"
"github.com/krateoplatformops/crdgen"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)

const (
defaultGroup = "composition.krateo.io"
)

func ChartInfoFromSpec(ctx context.Context, nfo *v1alpha1.ChartInfo) (pkg fs.FS, rootDir string, err error) {
func ChartInfoFromSpec(ctx context.Context, kube client.Client, nfo *v1alpha1.ChartInfo) (pkg fs.FS, rootDir string, err error) {
if nfo == nil {
return nil, "", fmt.Errorf("chart infos cannot be nil")
}

dat, _, err := getter.Get(getter.GetOptions{
opts := getter.GetOptions{
URI: nfo.Url,
Version: nfo.Version,
Repo: nfo.Repo,
})
Repo: nfo.Repo}
if nfo.Credentials != nil {
secret, err := resolvers.GetSecret(ctx, kube, nfo.Credentials.PasswordRef)
if err != nil {
return nil, "", fmt.Errorf("failed to get secret: %w", err)
}
opts.Username = nfo.Credentials.Username
opts.Password = secret
opts.PassCredentialsAll = true
}

dat, _, err := getter.Get(opts)
if err != nil {
return nil, "", err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,38 @@ package generator_test
import (
"context"
"fmt"
"os"
"path"
"testing"

"github.com/krateoplatformops/core-provider/apis/compositiondefinitions/v1alpha1"
"github.com/krateoplatformops/core-provider/internal/controllers/compositiondefinitions/generator"
"github.com/krateoplatformops/crdgen"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func TestJsonSchemaFromOCI(t *testing.T) {
nfo := v1alpha1.ChartInfo{
Url: "oci://registry-1.docker.io/bitnamicharts/redis",
Version: "18.0.1",
}
home, err := os.UserHomeDir()
if err != nil {
t.Fatal(err)
}

cfg, err := clientcmd.BuildConfigFromFlags("", path.Join(home, ".kube/config"))
if err != nil {
t.Fatal(err)
}

cli, err := client.New(cfg, client.Options{})
if err != nil {
t.Fatal(err)
}

pkg, rootdir, err := generator.ChartInfoFromSpec(context.TODO(), &nfo)
pkg, rootdir, err := generator.ChartInfoFromSpec(context.TODO(), cli, &nfo)
if err != nil {
t.Fatal(err)
}
Expand All @@ -40,7 +58,7 @@ func TestCRDGenFromOCI(t *testing.T) {
Version: "18.0.1",
}

pkg, dir, err := generator.ChartInfoFromSpec(context.TODO(), &nfo)
pkg, dir, err := generator.ChartInfoFromSpec(context.TODO(), nil, &nfo)
if err != nil {
t.Fatal(err)
}
Expand Down
11 changes: 11 additions & 0 deletions internal/helm/getter/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ func (g *ociGetter) Get(opts GetOptions) ([]byte, string, error) {
if err != nil {
return nil, "", err
}
if opts.PassCredentialsAll {
host := strings.Split(ref, "/")[0]
loginopts := []registry.LoginOption{
registry.LoginOptBasicAuth(opts.Username, opts.Password),
}
err := g.client.Login(host, loginopts...)
if err != nil {
return nil, "", fmt.Errorf("failed to login: %w", err)
}
defer g.client.Logout(host)
}

pullOpts := []registry.PullOption{
registry.PullOptWithChart(true),
Expand Down
2 changes: 1 addition & 1 deletion internal/helm/getter/tgz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

func TestTGZ(t *testing.T) {
const (
uri = "https://github.com/krateoplatformops/krateo-v2-template-fireworksapp/releases/download/0.0.1/fireworks-app-0.1.0.tgz"
uri = "https://github.com/krateoplatformops/krateo-v2-template-fireworksapp/releases/download/0.1.0/fireworks-app-0.1.0.tgz"
)

if !isTGZ(uri) {
Expand Down
21 changes: 17 additions & 4 deletions internal/tools/chartfs/chartfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package chartfs

import (
"bytes"
"context"
"fmt"
"io"
"io/fs"

"github.com/krateoplatformops/core-provider/apis/compositiondefinitions/v1alpha1"
"github.com/krateoplatformops/core-provider/internal/helm/getter"
"github.com/krateoplatformops/core-provider/internal/tgzfs"
"github.com/krateoplatformops/core-provider/internal/tools/resolvers"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func FromReader(in io.Reader, pkgurl string) (*ChartFS, error) {
Expand Down Expand Up @@ -40,16 +43,26 @@ func FromReader(in io.Reader, pkgurl string) (*ChartFS, error) {
}, nil
}

func ForSpec(nfo *v1alpha1.ChartInfo) (*ChartFS, error) {
func ForSpec(ctx context.Context, kube client.Client, nfo *v1alpha1.ChartInfo) (*ChartFS, error) {
if nfo == nil {
return nil, fmt.Errorf("chart infos cannot be nil")
}

dat, url, err := getter.Get(getter.GetOptions{
opts := getter.GetOptions{
URI: nfo.Url,
Version: nfo.Version,
Repo: nfo.Repo,
})
Repo: nfo.Repo}
if nfo.Credentials != nil {
secret, err := resolvers.GetSecret(ctx, kube, nfo.Credentials.PasswordRef)
if err != nil {
return nil, fmt.Errorf("failed to get secret: %w", err)
}

opts.Username = nfo.Credentials.Username
opts.Password = secret
opts.PassCredentialsAll = true
}
dat, url, err := getter.Get(opts)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/tools/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ type DeployOptions struct {
Log func(msg string, keysAndValues ...any)
}

func Deploy(ctx context.Context, opts DeployOptions) (err error, rbacErr error) {
pkg, err := chartfs.ForSpec(opts.Spec)
func Deploy(ctx context.Context, kube client.Client, opts DeployOptions) (err error, rbacErr error) {
pkg, err := chartfs.ForSpec(ctx, kube, opts.Spec)
if err != nil {
return err, nil
}
Expand Down
14 changes: 13 additions & 1 deletion internal/tools/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ package tools_test
import (
"context"
"os"
"path"
"testing"

"github.com/krateoplatformops/core-provider/apis/compositiondefinitions/v1alpha1"
"github.com/krateoplatformops/core-provider/internal/tools"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func TestDeploy(t *testing.T) {
Expand All @@ -24,8 +27,17 @@ func TestDeploy(t *testing.T) {
if err != nil {
t.Fatal(err)
}
home, err := os.UserHomeDir()
cfg, err := clientcmd.BuildConfigFromFlags("", path.Join(home, ".kube/config"))
if err != nil {
t.Fatal(err)
}
cli, err := client.New(cfg, client.Options{})
if err != nil {
t.Fatal(err)
}

err, _ = tools.Deploy(context.TODO(), tools.DeployOptions{
err, _ = tools.Deploy(context.TODO(), cli, tools.DeployOptions{
KubeClient: kube,
Spec: nfo,
NamespacedName: types.NamespacedName{
Expand Down
22 changes: 22 additions & 0 deletions internal/tools/resolvers/secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package resolvers

import (
"context"

rtv1 "github.com/krateoplatformops/provider-runtime/apis/common/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func GetSecret(ctx context.Context, kube client.Client, secretKeySelector rtv1.SecretKeySelector) (string, error) {
secret := &corev1.Secret{}
if err := kube.Get(ctx, types.NamespacedName{
Name: secretKeySelector.Name,
Namespace: secretKeySelector.Namespace,
}, secret); err != nil {
return "", err
}

return string(secret.Data[secretKeySelector.Key]), nil
}
Loading

0 comments on commit e55bfd5

Please sign in to comment.