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 --registry-creds flag to bootstrap and install commands #4706

Merged
merged 2 commits into from
Apr 8, 2024
Merged
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
6 changes: 6 additions & 0 deletions .github/workflows/e2e-bootstrap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,22 @@ jobs:
run: |
/tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--image-pull-secret=ghcr-auth \
--registry-creds=fluxcd:$GITHUB_TOKEN \
--repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \
--path=test-cluster \
--team=team-z
env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: verify image pull secret
run: |
kubectl -n flux-system get secret ghcr-auth | grep dockerconfigjson
- name: bootstrap no-op
run: |
/tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \
--image-pull-secret=ghcr-auth \
--repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \
--path=test-cluster \
Expand Down
15 changes: 13 additions & 2 deletions cmd/flux/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ type bootstrapFlags struct {
extraComponents []string
requiredComponents []string

registry string
imagePullSecret string
registry string
registryCredential string
imagePullSecret string

secretName string
tokenAuth bool
Expand Down Expand Up @@ -98,6 +99,8 @@ func init() {

bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd",
"container registry where the Flux controller images are published")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registryCredential, "registry-creds", "",
"container registry credentials in the format 'user:password', requires --image-pull-secret to be set")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.imagePullSecret, "image-pull-secret", "",
"Kubernetes secret name used for pulling the controller images from a private registry")

Expand Down Expand Up @@ -181,6 +184,14 @@ func bootstrapValidate() error {
return err
}

if bootstrapArgs.registryCredential != "" && bootstrapArgs.imagePullSecret == "" {
return fmt.Errorf("--registry-creds requires --image-pull-secret to be set")
}

if bootstrapArgs.registryCredential != "" && len(strings.Split(bootstrapArgs.registryCredential, ":")) != 2 {
return fmt.Errorf("invalid --registry-creds format, expected 'user:password'")
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions cmd/flux/bootstrap_bitbucket_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(),
Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy,
Expand Down
6 changes: 4 additions & 2 deletions cmd/flux/bootstrap_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ import (
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"

"github.com/fluxcd/pkg/git"
"github.com/fluxcd/pkg/git/gogit"

"github.com/fluxcd/flux2/v2/internal/flags"
"github.com/fluxcd/flux2/v2/internal/utils"
"github.com/fluxcd/flux2/v2/pkg/bootstrap"
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/install"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/sourcesecret"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/sync"
"github.com/fluxcd/pkg/git"
"github.com/fluxcd/pkg/git/gogit"
)

var bootstrapGitCmd = &cobra.Command{
Expand Down Expand Up @@ -201,6 +202,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(),
Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy,
Expand Down
1 change: 1 addition & 0 deletions cmd/flux/bootstrap_gitea.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ func bootstrapGiteaCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(),
Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy,
Expand Down
1 change: 1 addition & 0 deletions cmd/flux/bootstrap_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(),
Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy,
Expand Down
1 change: 1 addition & 0 deletions cmd/flux/bootstrap_gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(),
Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy,
Expand Down
39 changes: 39 additions & 0 deletions cmd/flux/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,20 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/yaml"

"github.com/fluxcd/flux2/v2/internal/flags"
"github.com/fluxcd/flux2/v2/internal/utils"
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/install"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/sourcesecret"
"github.com/fluxcd/flux2/v2/pkg/status"
)

Expand Down Expand Up @@ -66,6 +70,7 @@ type installFlags struct {
defaultComponents []string
extraComponents []string
registry string
registryCredential string
imagePullSecret string
branch string
watchAllNamespaces bool
Expand All @@ -92,6 +97,8 @@ func init() {
installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry,
"container registry where the toolkit images are published")
installCmd.Flags().StringVar(&installArgs.registryCredential, "registry-creds", "",
"container registry credentials in the format 'user:password', requires --image-pull-secret to be set")
installCmd.Flags().StringVar(&installArgs.imagePullSecret, "image-pull-secret", "",
"Kubernetes secret name used for pulling the toolkit images from a private registry")
installCmd.Flags().BoolVar(&installArgs.watchAllNamespaces, "watch-all-namespaces", rootArgs.defaults.WatchAllNamespaces,
Expand Down Expand Up @@ -124,6 +131,14 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
return err
}

if installArgs.registryCredential != "" && installArgs.imagePullSecret == "" {
return fmt.Errorf("--registry-creds requires --image-pull-secret to be set")
}

if installArgs.registryCredential != "" && len(strings.Split(installArgs.registryCredential, ":")) != 2 {
return fmt.Errorf("invalid --registry-creds format, expected 'user:password'")
}

if ver, err := getVersion(installArgs.version); err != nil {
return err
} else {
Expand Down Expand Up @@ -154,6 +169,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace,
Components: components,
Registry: installArgs.registry,
RegistryCredential: installArgs.registryCredential,
ImagePullSecret: installArgs.imagePullSecret,
WatchAllNamespaces: installArgs.watchAllNamespaces,
NetworkPolicy: installArgs.networkPolicy,
Expand Down Expand Up @@ -224,6 +240,29 @@ func installCmdRun(cmd *cobra.Command, args []string) error {

fmt.Fprintln(os.Stderr, applyOutput)

if opts.ImagePullSecret != "" && opts.RegistryCredential != "" {
logger.Actionf("generating image pull secret %s", opts.ImagePullSecret)
credentials := strings.SplitN(opts.RegistryCredential, ":", 2)
secretOpts := sourcesecret.Options{
Name: opts.ImagePullSecret,
Namespace: opts.Namespace,
Registry: opts.Registry,
Username: credentials[0],
Password: credentials[1],
}
imagePullSecret, err := sourcesecret.Generate(secretOpts)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
var s corev1.Secret
if err := yaml.Unmarshal([]byte(imagePullSecret.Content), &s); err != nil {
return fmt.Errorf("install failed: %w", err)
}
if err := upsertSecret(ctx, kubeClient, s); err != nil {
return fmt.Errorf("install failed: %w", err)
}
}

kubeConfig, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
if err != nil {
return fmt.Errorf("install failed: %w", err)
Expand Down
5 changes: 5 additions & 0 deletions cmd/flux/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ func TestInstall(t *testing.T) {
args: "install unexpectedPosArg --namespace=example",
assert: assertError(`unknown command "unexpectedPosArg" for "flux install"`),
},
{
name: "missing image pull secret",
args: "install --registry-creds=fluxcd:test",
assert: assertError(`--registry-creds requires --image-pull-secret to be set`),
},
}

for _, tt := range tests {
Expand Down
20 changes: 20 additions & 0 deletions pkg/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,26 @@ func reconcileSecret(ctx context.Context, kube client.Client, secret corev1.Secr
return kube.Update(ctx, &existing)
}

func reconcileImagePullSecret(ctx context.Context, kube client.Client, installOpts install.Options) error {
credentials := strings.SplitN(installOpts.RegistryCredential, ":", 2)
dcj, err := sourcesecret.GenerateDockerConfigJson(installOpts.Registry, credentials[0], credentials[1])
if err != nil {
return fmt.Errorf("failed to generate docker config json: %w", err)
}

secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: installOpts.Namespace,
Name: installOpts.ImagePullSecret,
},
StringData: map[string]string{
corev1.DockerConfigJsonKey: string(dcj),
},
Type: corev1.SecretTypeDockerConfigJson,
}
return reconcileSecret(ctx, kube, secret)
}

func kustomizationPathDiffers(ctx context.Context, kube client.Client, objKey client.ObjectKey, path string) (string, error) {
var k kustomizev1.Kustomization
if err := kube.Get(ctx, objKey, &k); err != nil {
Expand Down
8 changes: 8 additions & 0 deletions pkg/bootstrap/bootstrap_plain_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,14 @@ func (b *PlainGitBootstrapper) ReconcileComponents(ctx context.Context, manifest
b.logger.Successf("installed components")
}

// Reconcile image pull secret if needed
if options.ImagePullSecret != "" && options.RegistryCredential != "" {
souleb marked this conversation as resolved.
Show resolved Hide resolved
if err := reconcileImagePullSecret(ctx, b.kube, options); err != nil {
return fmt.Errorf("failed to reconcile image pull secret: %w", err)
}
b.logger.Successf("reconciled image pull secret %s", options.ImagePullSecret)
}

b.logger.Successf("reconciled components")
return nil
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/manifestgen/install/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Options struct {
ComponentsExtra []string
EventsAddr string
Registry string
RegistryCredential string
ImagePullSecret string
WatchAllNamespaces bool
NetworkPolicy bool
Expand All @@ -46,6 +47,7 @@ func MakeDefaultOptions() Options {
ComponentsExtra: []string{"image-reflector-controller", "image-automation-controller"},
EventsAddr: "",
Registry: "ghcr.io/fluxcd",
RegistryCredential: "",
ImagePullSecret: "",
WatchAllNamespaces: true,
NetworkPolicy: true,
Expand Down
4 changes: 2 additions & 2 deletions pkg/manifestgen/sourcesecret/sourcesecret.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func Generate(options Options) (*manifestgen.Manifest, error) {

var dockerCfgJson []byte
if options.Registry != "" {
dockerCfgJson, err = generateDockerConfigJson(options.Registry, options.Username, options.Password)
dockerCfgJson, err = GenerateDockerConfigJson(options.Registry, options.Username, options.Password)
if err != nil {
return nil, fmt.Errorf("failed to generate json for docker config: %w", err)
}
Expand Down Expand Up @@ -223,7 +223,7 @@ func resourceToString(data []byte) string {
return string(data)
}

func generateDockerConfigJson(url, username, password string) ([]byte, error) {
func GenerateDockerConfigJson(url, username, password string) ([]byte, error) {
cred := fmt.Sprintf("%s:%s", username, password)
auth := base64.StdEncoding.EncodeToString([]byte(cred))
cfg := DockerConfigJSON{
Expand Down
Loading