Generate image pull secret at bootstrap

Add an optional flag called `--registry-creds` to the bootstrap
command for generating an image pull secret for container images
stored in private registries.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
pull/4706/head
Stefan Prodan 9 months ago
parent afa648933b
commit 05903e2171
No known key found for this signature in database
GPG Key ID: 3299AEB0E4085BAF

@ -53,16 +53,22 @@ jobs:
run: | run: |
/tmp/flux bootstrap github --manifests ./manifests/install/ \ /tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \ --owner=fluxcd-testing \
--image-pull-secret=ghcr-auth \
--registry-creds=fluxcd:$GITHUB_TOKEN \
--repository=${{ steps.vars.outputs.test_repo_name }} \ --repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \ --branch=main \
--path=test-cluster \ --path=test-cluster \
--team=team-z --team=team-z
env: env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }} 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 - name: bootstrap no-op
run: | run: |
/tmp/flux bootstrap github --manifests ./manifests/install/ \ /tmp/flux bootstrap github --manifests ./manifests/install/ \
--owner=fluxcd-testing \ --owner=fluxcd-testing \
--image-pull-secret=ghcr-auth \
--repository=${{ steps.vars.outputs.test_repo_name }} \ --repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \ --branch=main \
--path=test-cluster \ --path=test-cluster \

@ -52,8 +52,9 @@ type bootstrapFlags struct {
extraComponents []string extraComponents []string
requiredComponents []string requiredComponents []string
registry string registry string
imagePullSecret string registryCredential string
imagePullSecret string
secretName string secretName string
tokenAuth bool tokenAuth bool
@ -98,6 +99,8 @@ func init() {
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd", bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd",
"container registry where the Flux controller images are published") "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", "", bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.imagePullSecret, "image-pull-secret", "",
"Kubernetes secret name used for pulling the controller images from a private registry") "Kubernetes secret name used for pulling the controller images from a private registry")
@ -181,6 +184,14 @@ func bootstrapValidate() error {
return err 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 return nil
} }

@ -196,6 +196,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces, WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy, NetworkPolicy: bootstrapArgs.networkPolicy,

@ -28,6 +28,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" 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/flags"
"github.com/fluxcd/flux2/v2/internal/utils" "github.com/fluxcd/flux2/v2/internal/utils"
"github.com/fluxcd/flux2/v2/pkg/bootstrap" "github.com/fluxcd/flux2/v2/pkg/bootstrap"
@ -35,8 +38,6 @@ import (
"github.com/fluxcd/flux2/v2/pkg/manifestgen/install" "github.com/fluxcd/flux2/v2/pkg/manifestgen/install"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/sourcesecret" "github.com/fluxcd/flux2/v2/pkg/manifestgen/sourcesecret"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/sync" "github.com/fluxcd/flux2/v2/pkg/manifestgen/sync"
"github.com/fluxcd/pkg/git"
"github.com/fluxcd/pkg/git/gogit"
) )
var bootstrapGitCmd = &cobra.Command{ var bootstrapGitCmd = &cobra.Command{
@ -201,6 +202,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces, WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy, NetworkPolicy: bootstrapArgs.networkPolicy,

@ -184,6 +184,7 @@ func bootstrapGiteaCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces, WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy, NetworkPolicy: bootstrapArgs.networkPolicy,

@ -191,6 +191,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces, WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy, NetworkPolicy: bootstrapArgs.networkPolicy,

@ -216,6 +216,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
Namespace: *kubeconfigArgs.Namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
RegistryCredential: bootstrapArgs.registryCredential,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces, WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
NetworkPolicy: bootstrapArgs.networkPolicy, NetworkPolicy: bootstrapArgs.networkPolicy,

@ -173,6 +173,26 @@ func reconcileSecret(ctx context.Context, kube client.Client, secret corev1.Secr
return kube.Update(ctx, &existing) 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) { func kustomizationPathDiffers(ctx context.Context, kube client.Client, objKey client.ObjectKey, path string) (string, error) {
var k kustomizev1.Kustomization var k kustomizev1.Kustomization
if err := kube.Get(ctx, objKey, &k); err != nil { if err := kube.Get(ctx, objKey, &k); err != nil {

@ -207,6 +207,14 @@ func (b *PlainGitBootstrapper) ReconcileComponents(ctx context.Context, manifest
b.logger.Successf("installed components") b.logger.Successf("installed components")
} }
// Reconcile image pull secret if needed
if options.ImagePullSecret != "" && options.RegistryCredential != "" {
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") b.logger.Successf("reconciled components")
return nil return nil
} }

@ -26,6 +26,7 @@ type Options struct {
ComponentsExtra []string ComponentsExtra []string
EventsAddr string EventsAddr string
Registry string Registry string
RegistryCredential string
ImagePullSecret string ImagePullSecret string
WatchAllNamespaces bool WatchAllNamespaces bool
NetworkPolicy bool NetworkPolicy bool
@ -46,6 +47,7 @@ func MakeDefaultOptions() Options {
ComponentsExtra: []string{"image-reflector-controller", "image-automation-controller"}, ComponentsExtra: []string{"image-reflector-controller", "image-automation-controller"},
EventsAddr: "", EventsAddr: "",
Registry: "ghcr.io/fluxcd", Registry: "ghcr.io/fluxcd",
RegistryCredential: "",
ImagePullSecret: "", ImagePullSecret: "",
WatchAllNamespaces: true, WatchAllNamespaces: true,
NetworkPolicy: true, NetworkPolicy: true,

@ -83,7 +83,7 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
var dockerCfgJson []byte var dockerCfgJson []byte
if options.Registry != "" { if options.Registry != "" {
dockerCfgJson, err = generateDockerConfigJson(options.Registry, options.Username, options.Password) dockerCfgJson, err = GenerateDockerConfigJson(options.Registry, options.Username, options.Password)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to generate json for docker config: %w", err) return nil, fmt.Errorf("failed to generate json for docker config: %w", err)
} }
@ -223,7 +223,7 @@ func resourceToString(data []byte) string {
return string(data) 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) cred := fmt.Sprintf("%s:%s", username, password)
auth := base64.StdEncoding.EncodeToString([]byte(cred)) auth := base64.StdEncoding.EncodeToString([]byte(cred))
cfg := DockerConfigJSON{ cfg := DockerConfigJSON{

Loading…
Cancel
Save