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>
This commit is contained in:
6
.github/workflows/e2e-bootstrap.yaml
vendored
6
.github/workflows/e2e-bootstrap.yaml
vendored
@@ -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{
|
||||||
|
|||||||
Reference in New Issue
Block a user