Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c312816858 | ||
|
|
e5635d0ae2 | ||
|
|
43372a9ac7 | ||
|
|
a46f4e36cf |
@@ -254,7 +254,6 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
bootstrap.WithKubeconfig(kubeconfigArgs),
|
bootstrap.WithKubeconfig(kubeconfigArgs),
|
||||||
bootstrap.WithLogger(logger),
|
bootstrap.WithLogger(logger),
|
||||||
bootstrap.WithCABundle(caBundle),
|
bootstrap.WithCABundle(caBundle),
|
||||||
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
|
|
||||||
}
|
}
|
||||||
if bootstrapArgs.sshHostname != "" {
|
if bootstrapArgs.sshHostname != "" {
|
||||||
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
||||||
|
|||||||
@@ -243,7 +243,6 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
bootstrap.WithKubeconfig(kubeconfigArgs),
|
bootstrap.WithKubeconfig(kubeconfigArgs),
|
||||||
bootstrap.WithLogger(logger),
|
bootstrap.WithLogger(logger),
|
||||||
bootstrap.WithCABundle(caBundle),
|
bootstrap.WithCABundle(caBundle),
|
||||||
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
|
|
||||||
}
|
}
|
||||||
if bootstrapArgs.sshHostname != "" {
|
if bootstrapArgs.sshHostname != "" {
|
||||||
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
||||||
|
|||||||
@@ -257,7 +257,6 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
bootstrap.WithKubeconfig(kubeconfigArgs),
|
bootstrap.WithKubeconfig(kubeconfigArgs),
|
||||||
bootstrap.WithLogger(logger),
|
bootstrap.WithLogger(logger),
|
||||||
bootstrap.WithCABundle(caBundle),
|
bootstrap.WithCABundle(caBundle),
|
||||||
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
|
|
||||||
}
|
}
|
||||||
if bootstrapArgs.sshHostname != "" {
|
if bootstrapArgs.sshHostname != "" {
|
||||||
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))
|
||||||
|
|||||||
@@ -49,40 +49,25 @@ mentioned in YAMLs in a git repository.`,
|
|||||||
--push-branch=image-updates \
|
--push-branch=image-updates \
|
||||||
--author-name=flux \
|
--author-name=flux \
|
||||||
--author-email=flux@example.com \
|
--author-email=flux@example.com \
|
||||||
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
|
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"`,
|
||||||
|
|
||||||
# Configure image updates for a Git repository in a different namespace
|
|
||||||
flux create image update apps \
|
|
||||||
--namespace=apps \
|
|
||||||
--git-repo-ref=flux-system \
|
|
||||||
--git-repo-namespace=flux-system \
|
|
||||||
--git-repo-path="./clusters/my-cluster" \
|
|
||||||
--checkout-branch=main \
|
|
||||||
--push-branch=image-updates \
|
|
||||||
--author-name=flux \
|
|
||||||
--author-email=flux@example.com \
|
|
||||||
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
|
|
||||||
`,
|
|
||||||
RunE: createImageUpdateRun,
|
RunE: createImageUpdateRun,
|
||||||
}
|
}
|
||||||
|
|
||||||
type imageUpdateFlags struct {
|
type imageUpdateFlags struct {
|
||||||
gitRepoName string
|
gitRepoRef string
|
||||||
gitRepoNamespace string
|
gitRepoPath string
|
||||||
gitRepoPath string
|
checkoutBranch string
|
||||||
checkoutBranch string
|
pushBranch string
|
||||||
pushBranch string
|
commitTemplate string
|
||||||
commitTemplate string
|
authorName string
|
||||||
authorName string
|
authorEmail string
|
||||||
authorEmail string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageUpdateArgs = imageUpdateFlags{}
|
var imageUpdateArgs = imageUpdateFlags{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flags := createImageUpdateCmd.Flags()
|
flags := createImageUpdateCmd.Flags()
|
||||||
flags.StringVar(&imageUpdateArgs.gitRepoName, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream Git repository")
|
flags.StringVar(&imageUpdateArgs.gitRepoRef, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream Git repository")
|
||||||
flags.StringVar(&imageUpdateArgs.gitRepoNamespace, "git-repo-namespace", "", "the namespace of the GitRepository resource, defaults to the ImageUpdateAutomation namespace")
|
|
||||||
flags.StringVar(&imageUpdateArgs.gitRepoPath, "git-repo-path", "", "path to the directory containing the manifests to be updated, defaults to the repository root")
|
flags.StringVar(&imageUpdateArgs.gitRepoPath, "git-repo-path", "", "path to the directory containing the manifests to be updated, defaults to the repository root")
|
||||||
flags.StringVar(&imageUpdateArgs.checkoutBranch, "checkout-branch", "", "the branch to checkout")
|
flags.StringVar(&imageUpdateArgs.checkoutBranch, "checkout-branch", "", "the branch to checkout")
|
||||||
flags.StringVar(&imageUpdateArgs.pushBranch, "push-branch", "", "the branch to push commits to, defaults to the checkout branch if not specified")
|
flags.StringVar(&imageUpdateArgs.pushBranch, "push-branch", "", "the branch to push commits to, defaults to the checkout branch if not specified")
|
||||||
@@ -99,7 +84,7 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
objectName := args[0]
|
objectName := args[0]
|
||||||
|
|
||||||
if imageUpdateArgs.gitRepoName == "" {
|
if imageUpdateArgs.gitRepoRef == "" {
|
||||||
return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)")
|
return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,9 +113,8 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
|
|||||||
},
|
},
|
||||||
Spec: autov1.ImageUpdateAutomationSpec{
|
Spec: autov1.ImageUpdateAutomationSpec{
|
||||||
SourceRef: autov1.CrossNamespaceSourceReference{
|
SourceRef: autov1.CrossNamespaceSourceReference{
|
||||||
Kind: sourcev1.GitRepositoryKind,
|
Kind: sourcev1.GitRepositoryKind,
|
||||||
Name: imageUpdateArgs.gitRepoName,
|
Name: imageUpdateArgs.gitRepoRef,
|
||||||
Namespace: imageUpdateArgs.gitRepoNamespace,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
GitSpec: &autov1.GitSpec{
|
GitSpec: &autov1.GitSpec{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
var diffCmd = &cobra.Command{
|
var diffCmd = &cobra.Command{
|
||||||
Use: "diff",
|
Use: "diff",
|
||||||
Short: "Diff a flux resource",
|
Short: "Diff a flux resource",
|
||||||
Long: "The diff command is used to do a server-side dry-run on flux resources, then prints the diff.",
|
Long: "The diff command is used to do a server-side dry-run on flux resources, then output the diff.",
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -31,9 +31,8 @@ var diffKsCmd = &cobra.Command{
|
|||||||
Use: "kustomization",
|
Use: "kustomization",
|
||||||
Aliases: []string{"ks"},
|
Aliases: []string{"ks"},
|
||||||
Short: "Diff Kustomization",
|
Short: "Diff Kustomization",
|
||||||
Long: `The diff command does a build, then it performs a server-side dry-run and prints the diff.
|
Long: `The diff command does a build, then it performs a server-side dry-run and output the diff.`,
|
||||||
Exit status: 0 No differences were found. 1 Differences were found. >1 diff failed with an error.`,
|
Example: `# Preview changes local changes as they were applied on the cluster
|
||||||
Example: `# Preview local changes as they were applied on the cluster
|
|
||||||
flux diff kustomization my-app --path ./path/to/local/manifests`,
|
flux diff kustomization my-app --path ./path/to/local/manifests`,
|
||||||
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
|
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
|
||||||
RunE: diffKsCmdRun,
|
RunE: diffKsCmdRun,
|
||||||
@@ -57,16 +56,16 @@ func diffKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
if diffKsArgs.path == "" {
|
if diffKsArgs.path == "" {
|
||||||
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)}
|
return fmt.Errorf("invalid resource path %q", diffKsArgs.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fs, err := os.Stat(diffKsArgs.path); err != nil || !fs.IsDir() {
|
if fs, err := os.Stat(diffKsArgs.path); err != nil || !fs.IsDir() {
|
||||||
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)}
|
return fmt.Errorf("invalid resource path %q", diffKsArgs.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
builder, err := build.NewBuilder(kubeconfigArgs, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout))
|
builder, err := build.NewBuilder(kubeconfigArgs, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &RequestError{StatusCode: 2, Err: err}
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a signal channel
|
// create a signal channel
|
||||||
@@ -75,18 +74,13 @@ func diffKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
output, hasChanged, err := builder.Diff()
|
output, err := builder.Diff()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- &RequestError{StatusCode: 2, Err: err}
|
errChan <- err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Print(output)
|
cmd.Print(output)
|
||||||
|
errChan <- nil
|
||||||
if hasChanged {
|
|
||||||
errChan <- &RequestError{StatusCode: 1, Err: fmt.Errorf("identified at least one change, exiting with non-zero exit code")}
|
|
||||||
} else {
|
|
||||||
errChan <- nil
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -79,18 +79,6 @@ func TestDiffKustomization(t *testing.T) {
|
|||||||
objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml",
|
objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml",
|
||||||
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"),
|
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "diff with a sops dockerconfigjson secret object",
|
|
||||||
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
|
|
||||||
objectFile: "./testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml",
|
|
||||||
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "diff with a sops stringdata secret object",
|
|
||||||
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo",
|
|
||||||
objectFile: "./testdata/diff-kustomization/stringdata-sops-secret.yaml",
|
|
||||||
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-stringdata-sops-secret.golden"),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl := map[string]string{
|
tmpl := map[string]string{
|
||||||
|
|||||||
@@ -105,16 +105,6 @@ type rootFlags struct {
|
|||||||
defaults install.Options
|
defaults install.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestError is a custom error type that wraps an error returned by the flux api.
|
|
||||||
type RequestError struct {
|
|
||||||
StatusCode int
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RequestError) Error() string {
|
|
||||||
return r.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
var rootArgs = NewRootFlags()
|
var rootArgs = NewRootFlags()
|
||||||
var kubeconfigArgs = genericclioptions.NewConfigFlags(false)
|
var kubeconfigArgs = genericclioptions.NewConfigFlags(false)
|
||||||
|
|
||||||
@@ -153,17 +143,6 @@ func NewRootFlags() rootFlags {
|
|||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
|
||||||
if err, ok := err.(*RequestError); ok {
|
|
||||||
if err.StatusCode == 1 {
|
|
||||||
logger.Warningf("%v", err)
|
|
||||||
} else {
|
|
||||||
logger.Failuref("%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Exit(err.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Failuref("%v", err)
|
logger.Failuref("%v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,12 +325,6 @@ type cmdTestCase struct {
|
|||||||
|
|
||||||
func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
|
func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
|
||||||
actual, testErr := executeCommand(cmd.args)
|
actual, testErr := executeCommand(cmd.args)
|
||||||
|
|
||||||
// If the cmd error is a change, discard it
|
|
||||||
if isChangeError(testErr) {
|
|
||||||
testErr = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if assertErr := cmd.assert(actual, testErr); assertErr != nil {
|
if assertErr := cmd.assert(actual, testErr); assertErr != nil {
|
||||||
t.Error(assertErr)
|
t.Error(assertErr)
|
||||||
}
|
}
|
||||||
@@ -372,12 +366,3 @@ func resetCmdArgs() {
|
|||||||
getArgs = GetFlags{}
|
getArgs = GetFlags{}
|
||||||
secretGitArgs = NewSecretGitFlags()
|
secretGitArgs = NewSecretGitFlags()
|
||||||
}
|
}
|
||||||
|
|
||||||
func isChangeError(err error) bool {
|
|
||||||
if reqErr, ok := err.(*RequestError); ok {
|
|
||||||
if strings.Contains(err.Error(), "identified at least one change, exiting with non-zero exit code") && reqErr.StatusCode == 1 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ func init() {
|
|||||||
|
|
||||||
type resumable interface {
|
type resumable interface {
|
||||||
adapter
|
adapter
|
||||||
copyable
|
|
||||||
statusable
|
statusable
|
||||||
setUnsuspended()
|
setUnsuspended()
|
||||||
successMessage() string
|
successMessage() string
|
||||||
@@ -98,13 +97,10 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
for i := 0; i < resume.list.len(); i++ {
|
for i := 0; i < resume.list.len(); i++ {
|
||||||
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
|
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
|
||||||
obj := resume.list.resumeItem(i)
|
resume.list.resumeItem(i).setUnsuspended()
|
||||||
patch := client.MergeFrom(obj.deepCopyClientObject())
|
if err := kubeClient.Update(ctx, resume.list.resumeItem(i).asClientObject()); err != nil {
|
||||||
obj.setUnsuspended()
|
|
||||||
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Successf("%s resumed", resume.humanKind)
|
logger.Successf("%s resumed", resume.humanKind)
|
||||||
|
|
||||||
namespacedName := types.NamespacedName{
|
namespacedName := types.NamespacedName{
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ func init() {
|
|||||||
|
|
||||||
type suspendable interface {
|
type suspendable interface {
|
||||||
adapter
|
adapter
|
||||||
copyable
|
|
||||||
isSuspended() bool
|
isSuspended() bool
|
||||||
setSuspended()
|
setSuspended()
|
||||||
}
|
}
|
||||||
@@ -95,11 +94,8 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
for i := 0; i < suspend.list.len(); i++ {
|
for i := 0; i < suspend.list.len(); i++ {
|
||||||
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, suspend.list.item(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
|
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, suspend.list.item(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
|
||||||
|
suspend.list.item(i).setSuspended()
|
||||||
obj := suspend.list.item(i)
|
if err := kubeClient.Update(ctx, suspend.list.item(i).asClientObject()); err != nil {
|
||||||
patch := client.MergeFrom(obj.deepCopyClientObject())
|
|
||||||
obj.setSuspended()
|
|
||||||
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("%s suspended", suspend.humanKind)
|
logger.Successf("%s suspended", suspend.humanKind)
|
||||||
|
|||||||
@@ -123,31 +123,6 @@ spec:
|
|||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
|
||||||
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
|
||||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
|
||||||
name: docker-secret
|
|
||||||
namespace: default
|
|
||||||
type: kubernetes.io/dockerconfigjson
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
|
||||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
|
||||||
name: secret-basic-auth-stringdata
|
|
||||||
namespace: default
|
|
||||||
stringData:
|
|
||||||
password: KipTT1BTKio=
|
|
||||||
username: KipTT1BTKio=
|
|
||||||
type: kubernetes.io/basic-auth
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
data:
|
data:
|
||||||
token: KipTT1BTKio=
|
token: KipTT1BTKio=
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
data:
|
|
||||||
.dockerconfigjson: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: docker-secret
|
|
||||||
type: kubernetes.io/dockerconfigjson
|
|
||||||
sops:
|
|
||||||
kms: []
|
|
||||||
gcp_kms: []
|
|
||||||
azure_kv: []
|
|
||||||
hc_vault: []
|
|
||||||
age:
|
|
||||||
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
|
|
||||||
enc: |
|
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3eU1CTEJhVXZ4eEVYYkVV
|
|
||||||
OU90TEcrR2pYckttN0pBanJoSUZWSW1RQXlRCkUydFJ3V1NZUTBuVFF0aC9GUEcw
|
|
||||||
bUdhNjJWTkoyL1FUVi9Dc1dxUDBkM0UKLS0tIE1sQXkwcWdGaEFuY0RHQTVXM0J6
|
|
||||||
dWpJcThEbW15V3dXYXpPZklBdW1Hd1kKoIAdmGNPrEctV8h1w8KuvQ5S+BGmgqN9
|
|
||||||
MgpNmUhJjWhgcQpb5BRYpQesBOgU5TBGK7j58A6DMDKlSiYZsdQchQ==
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
|
||||||
lastmodified: "2022-02-03T16:03:17Z"
|
|
||||||
mac: ENC[AES256_GCM,data:AHdYSawajwgAFwlmDN1IPNmT9vWaYKzyVIra2d6sPcjTbZ8/p+VRSRpVm4XZFFsaNnW5AUJaouwXnKYDTmJDXKlr/rQcu9kXqsssQgdzcXaA6l5uJlgsnml8ba7J3OK+iEKMax23mwQEx2EUskCd9ENOwFDkunP02sxqDNOz20k=,iv:8F5OamHt3fAVorf6p+SoIrWoqkcATSGWVoM0EK87S4M=,tag:E1mxXnc7wWkEX5BxhpLtng==,type:str]
|
|
||||||
pgp: []
|
|
||||||
encrypted_regex: ^(data|stringData)$
|
|
||||||
version: 3.7.1
|
|
||||||
@@ -4,8 +4,6 @@ resources:
|
|||||||
- ./deployment.yaml
|
- ./deployment.yaml
|
||||||
- ./hpa.yaml
|
- ./hpa.yaml
|
||||||
- ./service.yaml
|
- ./service.yaml
|
||||||
- ./dockerconfigjson-sops-secret.yaml
|
|
||||||
- ./stringdata-secret.yaml
|
|
||||||
secretGenerator:
|
secretGenerator:
|
||||||
- files:
|
- files:
|
||||||
- token=token.encrypted
|
- token=token.encrypted
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: secret-basic-auth-stringdata
|
|
||||||
type: kubernetes.io/basic-auth
|
|
||||||
stringData:
|
|
||||||
username: ENC[AES256_GCM,data:uKiQR48=,iv:jh2lgyAVu7igJAgoJsnOGhjxFyvUAa9lvT21u3hhqpU=,tag:zXM2JEpk3ZEH7WfkcWXXkw==,type:str]
|
|
||||||
password: ENC[AES256_GCM,data:PyhZmNhy929JGQ==,iv:PBqPaJmSw21+kn4gIlg5VdjLNZyf613z5RUTCesBoVw=,tag:Hjc7DsuUrtsz7PYPdNkL3g==,type:str]
|
|
||||||
sops:
|
|
||||||
kms: []
|
|
||||||
gcp_kms: []
|
|
||||||
azure_kv: []
|
|
||||||
hc_vault: []
|
|
||||||
age:
|
|
||||||
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
|
|
||||||
enc: |
|
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJd0xxbDZhYjVoZzY4YWhK
|
|
||||||
d2NvMVgrSGRVUGhHRGg3R1FpVURnbmh1TDBzCjcwby85M3JaK09QVk0yZFNMb2NL
|
|
||||||
c2NQZW5hS1FhYlBHU0VoUzBVYzZYUUUKLS0tIEdaNEw2Y0VjVHpZc3pyYUtLVmJk
|
|
||||||
NmN3K2VLU0NiZ1d0VHBYbGlCM1lrNmMKeWz3yfFbMNE+ly21oLfc1XnDSPRmnlPP
|
|
||||||
wIs8lk/qrzVZ45C9GdWnnPeGZZiia46Yop9TxseUS8gCjJ6KCxJCAg==
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
|
||||||
lastmodified: "2022-02-06T12:51:07Z"
|
|
||||||
mac: ENC[AES256_GCM,data:jtdzwj19uxdxvnmXg1HkAkDA6XlKMJOYFy7uLI5t/t11LwGop5Yeo7a4nQEEELehRx9J7B6U6NiySxAxBxWx5uW5vI5c8+069VV6dkiCIefnYSzuoIhQafjlFl1/KvH7VEjIWfHYuXF09v9PEKXkxEHUYDpS3QqQ3ymHRRI08pU=, iv:xX3E7F+AM29Pm8G5oqxRfYu9E7tEBGIaHeCJYgrtFmc=,tag:MJPGusNvu05z939jg8PAwQ==,type:str]
|
|
||||||
pgp: []
|
|
||||||
encrypted_regex: ^(data|stringData)$
|
|
||||||
version: 3.7.1
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
► HorizontalPodAutoscaler/default/podinfo created
|
► HorizontalPodAutoscaler/default/podinfo created
|
||||||
► Service/default/podinfo created
|
► Service/default/podinfo created
|
||||||
► Secret/default/docker-secret created
|
|
||||||
► Secret/default/secret-basic-auth-stringdata created
|
|
||||||
► Secret/default/podinfo-token-77t89m9b67 created
|
► Secret/default/podinfo-token-77t89m9b67 created
|
||||||
► Secret/default/db-user-pass-bkbd782d2c created
|
► Secret/default/db-user-pass-bkbd782d2c created
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
► Deployment/default/podinfo created
|
|
||||||
► HorizontalPodAutoscaler/default/podinfo created
|
|
||||||
► Service/default/podinfo created
|
|
||||||
► Secret/default/secret-basic-auth-stringdata created
|
|
||||||
► Secret/default/podinfo-token-77t89m9b67 created
|
|
||||||
► Secret/default/db-user-pass-bkbd782d2c created
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
► Deployment/default/podinfo created
|
► Deployment/default/podinfo created
|
||||||
► HorizontalPodAutoscaler/default/podinfo created
|
► HorizontalPodAutoscaler/default/podinfo created
|
||||||
► Service/default/podinfo created
|
► Service/default/podinfo created
|
||||||
► Secret/default/docker-secret created
|
|
||||||
► Secret/default/secret-basic-auth-stringdata created
|
|
||||||
► Secret/default/podinfo-token-77t89m9b67 drifted
|
► Secret/default/podinfo-token-77t89m9b67 drifted
|
||||||
|
|
||||||
data
|
data
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
► Deployment/default/podinfo created
|
► Deployment/default/podinfo created
|
||||||
► HorizontalPodAutoscaler/default/podinfo created
|
► HorizontalPodAutoscaler/default/podinfo created
|
||||||
► Service/default/podinfo created
|
► Service/default/podinfo created
|
||||||
► Secret/default/docker-secret created
|
|
||||||
► Secret/default/secret-basic-auth-stringdata created
|
|
||||||
► Secret/default/podinfo-token-77t89m9b67 created
|
► Secret/default/podinfo-token-77t89m9b67 created
|
||||||
► Secret/default/db-user-pass-bkbd782d2c drifted
|
► Secret/default/db-user-pass-bkbd782d2c drifted
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,5 @@ spec.ports.http.port
|
|||||||
- 9899
|
- 9899
|
||||||
+ 9898
|
+ 9898
|
||||||
|
|
||||||
► Secret/default/docker-secret created
|
|
||||||
► Secret/default/secret-basic-auth-stringdata created
|
|
||||||
► Secret/default/podinfo-token-77t89m9b67 created
|
► Secret/default/podinfo-token-77t89m9b67 created
|
||||||
► Secret/default/db-user-pass-bkbd782d2c created
|
► Secret/default/db-user-pass-bkbd782d2c created
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
► Deployment/default/podinfo created
|
► Deployment/default/podinfo created
|
||||||
► HorizontalPodAutoscaler/default/podinfo created
|
► HorizontalPodAutoscaler/default/podinfo created
|
||||||
► Service/default/podinfo created
|
► Service/default/podinfo created
|
||||||
► Secret/default/docker-secret created
|
|
||||||
► Secret/default/secret-basic-auth-stringdata created
|
|
||||||
► Secret/default/db-user-pass-bkbd782d2c created
|
► Secret/default/db-user-pass-bkbd782d2c created
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
► Deployment/default/podinfo created
|
|
||||||
► HorizontalPodAutoscaler/default/podinfo created
|
|
||||||
► Service/default/podinfo created
|
|
||||||
► Secret/default/docker-secret created
|
|
||||||
► Secret/default/podinfo-token-77t89m9b67 created
|
|
||||||
► Secret/default/db-user-pass-bkbd782d2c created
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
data:
|
|
||||||
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
|
||||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
|
||||||
name: docker-secret
|
|
||||||
namespace: default
|
|
||||||
type: kubernetes.io/dockerconfigjson
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
► Deployment/default/podinfo created
|
► Deployment/default/podinfo created
|
||||||
► HorizontalPodAutoscaler/default/podinfo created
|
► HorizontalPodAutoscaler/default/podinfo created
|
||||||
► Service/default/podinfo created
|
► Service/default/podinfo created
|
||||||
► Secret/default/docker-secret created
|
|
||||||
► Secret/default/secret-basic-auth-stringdata created
|
|
||||||
► Secret/default/podinfo-token-77t89m9b67 created
|
► Secret/default/podinfo-token-77t89m9b67 created
|
||||||
► Secret/default/db-user-pass-bkbd782d2c created
|
► Secret/default/db-user-pass-bkbd782d2c created
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
kustomize.toolkit.fluxcd.io/name: podinfo
|
|
||||||
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
|
|
||||||
name: secret-basic-auth-stringdata
|
|
||||||
namespace: default
|
|
||||||
stringData:
|
|
||||||
password: KipTT1BTKio=
|
|
||||||
username: KipTT1BTKio=
|
|
||||||
type: kubernetes.io/basic-auth
|
|
||||||
2
cmd/flux/testdata/export/git-repo.yaml
vendored
2
cmd/flux/testdata/export/git-repo.yaml
vendored
@@ -11,6 +11,6 @@ spec:
|
|||||||
branch: main
|
branch: main
|
||||||
secretRef:
|
secretRef:
|
||||||
name: flux-system
|
name: flux-system
|
||||||
timeout: 1m0s
|
timeout: 20s
|
||||||
url: ssh://git@github.com/example/repo
|
url: ssh://git@github.com/example/repo
|
||||||
|
|
||||||
|
|||||||
12
go.mod
12
go.mod
@@ -10,23 +10,23 @@ require (
|
|||||||
github.com/fluxcd/helm-controller/api v0.16.0
|
github.com/fluxcd/helm-controller/api v0.16.0
|
||||||
github.com/fluxcd/image-automation-controller/api v0.20.0
|
github.com/fluxcd/image-automation-controller/api v0.20.0
|
||||||
github.com/fluxcd/image-reflector-controller/api v0.16.0
|
github.com/fluxcd/image-reflector-controller/api v0.16.0
|
||||||
github.com/fluxcd/kustomize-controller/api v0.20.2
|
github.com/fluxcd/kustomize-controller/api v0.20.0
|
||||||
github.com/fluxcd/notification-controller/api v0.21.0
|
github.com/fluxcd/notification-controller/api v0.21.0
|
||||||
github.com/fluxcd/pkg/apis/kustomize v0.3.1 // indirect
|
github.com/fluxcd/pkg/apis/kustomize v0.3.1 // indirect
|
||||||
github.com/fluxcd/pkg/apis/meta v0.10.2
|
github.com/fluxcd/pkg/apis/meta v0.10.2
|
||||||
github.com/fluxcd/pkg/kustomize v0.0.2
|
github.com/fluxcd/pkg/kustomize v0.0.2
|
||||||
github.com/fluxcd/pkg/runtime v0.12.4
|
github.com/fluxcd/pkg/runtime v0.12.4
|
||||||
github.com/fluxcd/pkg/ssa v0.13.0
|
github.com/fluxcd/pkg/ssa v0.12.0
|
||||||
github.com/fluxcd/pkg/ssh v0.3.1
|
github.com/fluxcd/pkg/ssh v0.3.1
|
||||||
github.com/fluxcd/pkg/untar v0.0.5
|
github.com/fluxcd/pkg/untar v0.0.5
|
||||||
github.com/fluxcd/pkg/version v0.0.1
|
github.com/fluxcd/pkg/version v0.0.1
|
||||||
github.com/fluxcd/source-controller/api v0.21.2
|
github.com/fluxcd/source-controller/api v0.21.1
|
||||||
github.com/go-git/go-git/v5 v5.4.2
|
github.com/go-git/go-git/v5 v5.4.2
|
||||||
github.com/gonvenience/bunt v1.3.2
|
github.com/gonvenience/bunt v1.3.2
|
||||||
github.com/gonvenience/ytbx v1.4.2
|
github.com/gonvenience/ytbx v1.4.2
|
||||||
github.com/google/go-cmp v0.5.6
|
github.com/google/go-cmp v0.5.6
|
||||||
github.com/google/go-containerregistry v0.2.0
|
github.com/google/go-containerregistry v0.2.0
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||||
github.com/homeport/dyff v1.4.6
|
github.com/homeport/dyff v1.4.6
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0
|
github.com/lucasb-eyer/go-colorful v1.2.0
|
||||||
@@ -45,8 +45,8 @@ require (
|
|||||||
k8s.io/kubectl v0.23.1
|
k8s.io/kubectl v0.23.1
|
||||||
sigs.k8s.io/cli-utils v0.27.0
|
sigs.k8s.io/cli-utils v0.27.0
|
||||||
sigs.k8s.io/controller-runtime v0.11.0
|
sigs.k8s.io/controller-runtime v0.11.0
|
||||||
sigs.k8s.io/kustomize/api v0.11.2
|
sigs.k8s.io/kustomize/api v0.10.1
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.3
|
sigs.k8s.io/kustomize/kyaml v0.13.0
|
||||||
sigs.k8s.io/yaml v1.3.0
|
sigs.k8s.io/yaml v1.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
18
go.sum
18
go.sum
@@ -230,8 +230,8 @@ github.com/fluxcd/image-automation-controller/api v0.20.0 h1:Z+lxqif0KwccsuNOBZq
|
|||||||
github.com/fluxcd/image-automation-controller/api v0.20.0/go.mod h1:XhLYccGUbmJvTTpJ1jAFKZHr2e1GNXy0T85ZBO50mik=
|
github.com/fluxcd/image-automation-controller/api v0.20.0/go.mod h1:XhLYccGUbmJvTTpJ1jAFKZHr2e1GNXy0T85ZBO50mik=
|
||||||
github.com/fluxcd/image-reflector-controller/api v0.16.0 h1:1O1YdoK7LsJgWLyvfZTSbvQcUQCBcgJ573HA0arlQQY=
|
github.com/fluxcd/image-reflector-controller/api v0.16.0 h1:1O1YdoK7LsJgWLyvfZTSbvQcUQCBcgJ573HA0arlQQY=
|
||||||
github.com/fluxcd/image-reflector-controller/api v0.16.0/go.mod h1:OIe3mSXc3OwQiNbiQ9vNXWYtNif31hc7WAbZWlFUUnc=
|
github.com/fluxcd/image-reflector-controller/api v0.16.0/go.mod h1:OIe3mSXc3OwQiNbiQ9vNXWYtNif31hc7WAbZWlFUUnc=
|
||||||
github.com/fluxcd/kustomize-controller/api v0.20.2 h1:zqCvKGsNCL10WMfmjk2Sd526J6gv8ml027DwesFoZsc=
|
github.com/fluxcd/kustomize-controller/api v0.20.0 h1:Vw+2qCxeHMv0y1mfiBgVrMfcfFevBMrRfLEdfPTrb40=
|
||||||
github.com/fluxcd/kustomize-controller/api v0.20.2/go.mod h1:5MdpzJVx8+KiDIRv37zLme992BAOCgE0v1n+NOgs1lo=
|
github.com/fluxcd/kustomize-controller/api v0.20.0/go.mod h1:5MdpzJVx8+KiDIRv37zLme992BAOCgE0v1n+NOgs1lo=
|
||||||
github.com/fluxcd/notification-controller/api v0.21.0 h1:D5B3TH5YtSww0SyvW1Ru5xWsh0MgHQanC/a1t3CvXq0=
|
github.com/fluxcd/notification-controller/api v0.21.0 h1:D5B3TH5YtSww0SyvW1Ru5xWsh0MgHQanC/a1t3CvXq0=
|
||||||
github.com/fluxcd/notification-controller/api v0.21.0/go.mod h1:gA9/j0kjh7VDuUC2Cubr9twxOdzb/0+ojcE9Lzsc9ug=
|
github.com/fluxcd/notification-controller/api v0.21.0/go.mod h1:gA9/j0kjh7VDuUC2Cubr9twxOdzb/0+ojcE9Lzsc9ug=
|
||||||
github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc=
|
github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc=
|
||||||
@@ -245,8 +245,8 @@ github.com/fluxcd/pkg/kustomize v0.0.2/go.mod h1:AFwnf3OqQmpTCuwCARTGpPRMBf0ZFJN
|
|||||||
github.com/fluxcd/pkg/runtime v0.12.3/go.mod h1:imJ2xYy/d4PbSinX2IefmZk+iS2c1P5fY0js8mCE4SM=
|
github.com/fluxcd/pkg/runtime v0.12.3/go.mod h1:imJ2xYy/d4PbSinX2IefmZk+iS2c1P5fY0js8mCE4SM=
|
||||||
github.com/fluxcd/pkg/runtime v0.12.4 h1:gA27RG/+adN2/7Qe03PB46Iwmye/MusPCpuS4zQ2fW0=
|
github.com/fluxcd/pkg/runtime v0.12.4 h1:gA27RG/+adN2/7Qe03PB46Iwmye/MusPCpuS4zQ2fW0=
|
||||||
github.com/fluxcd/pkg/runtime v0.12.4/go.mod h1:gspNvhAqodZgSmK1ZhMtvARBf/NGAlxmaZaIOHkJYsc=
|
github.com/fluxcd/pkg/runtime v0.12.4/go.mod h1:gspNvhAqodZgSmK1ZhMtvARBf/NGAlxmaZaIOHkJYsc=
|
||||||
github.com/fluxcd/pkg/ssa v0.13.0 h1:LU4wf7dB9ksYdda0BEWNTBSTd68E5YwWxuPiPLAtw4Y=
|
github.com/fluxcd/pkg/ssa v0.12.0 h1:7nF4UigU9Zk/9P/nbzUP3ah8IRC+BpB64O9iu5VnvEo=
|
||||||
github.com/fluxcd/pkg/ssa v0.13.0/go.mod h1:XGVGjUaG152HGN6sSUj+VFK/Th5i5rj2XsXSDdlIMNU=
|
github.com/fluxcd/pkg/ssa v0.12.0/go.mod h1:S+qig7BTOxop0c134y8Yv8/iQST4Kt7S2xXiFkP4VMA=
|
||||||
github.com/fluxcd/pkg/ssh v0.3.1 h1:iQw07bkX2rScactX8WYv+uMDsufFOlg8M3fV2TNs244=
|
github.com/fluxcd/pkg/ssh v0.3.1 h1:iQw07bkX2rScactX8WYv+uMDsufFOlg8M3fV2TNs244=
|
||||||
github.com/fluxcd/pkg/ssh v0.3.1/go.mod h1:Sebfv4Um51PvomuYdMvKRncQW5dtKhZ5J5TA+wiHNSQ=
|
github.com/fluxcd/pkg/ssh v0.3.1/go.mod h1:Sebfv4Um51PvomuYdMvKRncQW5dtKhZ5J5TA+wiHNSQ=
|
||||||
github.com/fluxcd/pkg/untar v0.0.5 h1:UGI3Ch1UIEIaqQvMicmImL1s9npQa64DJ/ozqHKB7gk=
|
github.com/fluxcd/pkg/untar v0.0.5 h1:UGI3Ch1UIEIaqQvMicmImL1s9npQa64DJ/ozqHKB7gk=
|
||||||
@@ -254,8 +254,8 @@ github.com/fluxcd/pkg/untar v0.0.5/go.mod h1:O6V9+rtl8c1mHBafgqFlJN6zkF1HS5SSYn7
|
|||||||
github.com/fluxcd/pkg/version v0.0.1 h1:/8asQoDXSThz3csiwi4Qo8Zb6blAxLXbtxNgeMJ9bCg=
|
github.com/fluxcd/pkg/version v0.0.1 h1:/8asQoDXSThz3csiwi4Qo8Zb6blAxLXbtxNgeMJ9bCg=
|
||||||
github.com/fluxcd/pkg/version v0.0.1/go.mod h1:WAF4FEEA9xyhngF8TDxg3UPu5fA1qhEYV8Pmi2Il01Q=
|
github.com/fluxcd/pkg/version v0.0.1/go.mod h1:WAF4FEEA9xyhngF8TDxg3UPu5fA1qhEYV8Pmi2Il01Q=
|
||||||
github.com/fluxcd/source-controller/api v0.21.0/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
github.com/fluxcd/source-controller/api v0.21.0/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
||||||
github.com/fluxcd/source-controller/api v0.21.2 h1:J0S5NN4V8FPLrkSMXIUoUvj1X/RuTpVJSjIRF414wmc=
|
github.com/fluxcd/source-controller/api v0.21.1 h1:7X39YQHmB1vmIBrHxU+YAqxwtdC9Zh+tdtMKREW3xiQ=
|
||||||
github.com/fluxcd/source-controller/api v0.21.2/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
github.com/fluxcd/source-controller/api v0.21.1/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
||||||
@@ -1411,18 +1411,16 @@ sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNza
|
|||||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
|
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
|
||||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
||||||
sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g=
|
sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g=
|
||||||
|
sigs.k8s.io/kustomize/api v0.10.1 h1:KgU7hfYoscuqag84kxtzKdEC3mKMb99DPI3a0eaV1d0=
|
||||||
sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8=
|
sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8=
|
||||||
sigs.k8s.io/kustomize/api v0.11.2 h1:6YvCJHFDwsLwAX7zNHBxMZi3k7dGIXI8G9l0saYQI0E=
|
|
||||||
sigs.k8s.io/kustomize/api v0.11.2/go.mod h1:GZuhith5YcqxIDe0GnRJNx5xxPTjlwaLTt/e+ChUtJA=
|
|
||||||
sigs.k8s.io/kustomize/cmd/config v0.9.13/go.mod h1:7547FLF8W/lTaDf0BDqFTbZxM9zqwEJqCKN9sSR0xSs=
|
sigs.k8s.io/kustomize/cmd/config v0.9.13/go.mod h1:7547FLF8W/lTaDf0BDqFTbZxM9zqwEJqCKN9sSR0xSs=
|
||||||
sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ=
|
sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ=
|
||||||
sigs.k8s.io/kustomize/kustomize/v4 v4.2.0/go.mod h1:MOkR6fmhwG7hEDRXBYELTi5GSFcLwfqwzTRHW3kv5go=
|
sigs.k8s.io/kustomize/kustomize/v4 v4.2.0/go.mod h1:MOkR6fmhwG7hEDRXBYELTi5GSFcLwfqwzTRHW3kv5go=
|
||||||
sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io=
|
sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM=
|
sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.12.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
|
sigs.k8s.io/kustomize/kyaml v0.12.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
|
sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.3 h1:tNNQIC+8cc+aXFTVg+RtQAOsjwUdYBZRAgYOVI3RBc4=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.3/go.mod h1:/ya3Gk4diiQzlE4mBh7wykyLRFZNvqlbh+JnwQ9Vhrc=
|
|
||||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ=
|
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ=
|
||||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ func (b *GitProviderBootstrapper) reconcileOrgRepository(ctx context.Context) (g
|
|||||||
subOrgs, repoName := splitSubOrganizationsFromRepositoryName(b.repositoryName)
|
subOrgs, repoName := splitSubOrganizationsFromRepositoryName(b.repositoryName)
|
||||||
orgRef, err := b.getOrganization(ctx, subOrgs)
|
orgRef, err := b.getOrganization(ctx, subOrgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create new Git repository %q: %w", b.repositoryName, err)
|
return nil, fmt.Errorf("failed to create new Git repository for the organization %q: %w", orgRef.String(), err)
|
||||||
}
|
}
|
||||||
repoRef := newOrgRepositoryRef(*orgRef, repoName)
|
repoRef := newOrgRepositoryRef(*orgRef, repoName)
|
||||||
repoInfo := newRepositoryInfo(b.description, b.defaultBranch, b.visibility)
|
repoInfo := newRepositoryInfo(b.description, b.defaultBranch, b.visibility)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -37,17 +36,12 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
controllerName = "kustomize-controller"
|
controllerName = "kustomize-controller"
|
||||||
controllerGroup = "kustomize.toolkit.fluxcd.io"
|
controllerGroup = "kustomize.toolkit.fluxcd.io"
|
||||||
mask = "**SOPS**"
|
mask = "**SOPS**"
|
||||||
dockercfgSecretType = "kubernetes.io/dockerconfigjson"
|
|
||||||
typeField = "type"
|
|
||||||
dataField = "data"
|
|
||||||
stringDataField = "stringData"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultTimeout = 80 * time.Second
|
var defaultTimeout = 80 * time.Second
|
||||||
@@ -188,7 +182,7 @@ func (b *Builder) build() (m resmap.ResMap, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure secrets are masked
|
// make sure secrets are masked
|
||||||
err = maskSopsData(res)
|
err = trimSopsData(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -262,131 +256,26 @@ func (b *Builder) setOwnerLabels(res *resource.Resource) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func maskSopsData(res *resource.Resource) error {
|
func trimSopsData(res *resource.Resource) error {
|
||||||
// sopsMess is the base64 encoded mask
|
// sopsMess is the base64 encoded mask
|
||||||
sopsMess := base64.StdEncoding.EncodeToString([]byte(mask))
|
sopsMess := base64.StdEncoding.EncodeToString([]byte(mask))
|
||||||
|
|
||||||
if res.GetKind() == "Secret" {
|
if res.GetKind() == "Secret" {
|
||||||
// get both data and stringdata maps as a secret can have both
|
|
||||||
dataMap := res.GetDataMap()
|
dataMap := res.GetDataMap()
|
||||||
stringDataMap := getStringDataMap(res)
|
for k, v := range dataMap {
|
||||||
asYaml, err := res.AsYAML()
|
data, err := base64.StdEncoding.DecodeString(v)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete any sops data as we don't want to expose it
|
|
||||||
// assume that both data and stringdata are encrypted
|
|
||||||
if bytes.Contains(asYaml, []byte("sops:")) && bytes.Contains(asYaml, []byte("mac: ENC[")) {
|
|
||||||
// delete the sops object
|
|
||||||
res.PipeE(yaml.FieldClearer{Name: "sops"})
|
|
||||||
|
|
||||||
secretType, err := res.GetFieldValue(typeField)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
if _, ok := err.(base64.CorruptInputError); ok {
|
||||||
|
return fmt.Errorf("failed to decode secret data: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := secretType.(string); ok && v == dockercfgSecretType {
|
if bytes.Contains(data, []byte("sops")) && bytes.Contains(data, []byte("ENC[")) {
|
||||||
// if the secret is a json docker config secret, we need to mask the data with a json object
|
dataMap[k] = sopsMess
|
||||||
err := maskDockerconfigjsonSopsData(dataMap)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = maskDockerconfigjsonSopsData(stringDataMap)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
for k := range dataMap {
|
|
||||||
dataMap[k] = sopsMess
|
|
||||||
}
|
|
||||||
|
|
||||||
for k := range stringDataMap {
|
|
||||||
stringDataMap[k] = sopsMess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := maskBase64EncryptedSopsData(dataMap, sopsMess)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = maskSopsDataInStringDataSecret(stringDataMap, sopsMess)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the data and stringdata maps
|
|
||||||
res.SetDataMap(dataMap)
|
res.SetDataMap(dataMap)
|
||||||
|
|
||||||
if len(stringDataMap) > 0 {
|
|
||||||
err = res.SetMapField(yaml.NewMapRNode(&stringDataMap), stringDataField)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStringDataMap(rn *resource.Resource) map[string]string {
|
|
||||||
n, err := rn.Pipe(yaml.Lookup(stringDataField))
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := map[string]string{}
|
|
||||||
_ = n.VisitFields(func(node *yaml.MapNode) error {
|
|
||||||
result[yaml.GetValue(node.Key)] = yaml.GetValue(node.Value)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func maskDockerconfigjsonSopsData(dataMap map[string]string) error {
|
|
||||||
sopsMess := struct {
|
|
||||||
Mask string `json:"mask"`
|
|
||||||
}{
|
|
||||||
Mask: mask,
|
|
||||||
}
|
|
||||||
|
|
||||||
maskJson, err := json.Marshal(sopsMess)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for k := range dataMap {
|
|
||||||
dataMap[k] = base64.StdEncoding.EncodeToString(maskJson)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func maskBase64EncryptedSopsData(dataMap map[string]string, mask string) error {
|
|
||||||
for k, v := range dataMap {
|
|
||||||
data, err := base64.StdEncoding.DecodeString(v)
|
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(base64.CorruptInputError); ok {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes.Contains(data, []byte("sops")) && bytes.Contains(data, []byte("ENC[")) {
|
|
||||||
dataMap[k] = mask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func maskSopsDataInStringDataSecret(stringDataMap map[string]string, mask string) error {
|
|
||||||
for k, v := range stringDataMap {
|
|
||||||
if bytes.Contains([]byte(v), []byte("sops")) && bytes.Contains([]byte(v), []byte("ENC[")) {
|
|
||||||
stringDataMap[k] = mask
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -91,45 +91,6 @@ kind: Secret
|
|||||||
metadata:
|
metadata:
|
||||||
name: secret-basic-auth
|
name: secret-basic-auth
|
||||||
type: kubernetes.io/basic-auth
|
type: kubernetes.io/basic-auth
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "secret sops secret",
|
|
||||||
yamlStr: `apiVersion: v1
|
|
||||||
data:
|
|
||||||
.dockerconfigjson: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: secret
|
|
||||||
type: kubernetes.io/dockerconfigjson
|
|
||||||
sops:
|
|
||||||
kms: []
|
|
||||||
gcp_kms: []
|
|
||||||
azure_kv: []
|
|
||||||
hc_vault: []
|
|
||||||
age:
|
|
||||||
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
|
|
||||||
enc: |
|
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3eU1CTEJhVXZ4eEVYYkVV
|
|
||||||
OU90TEcrR2pYckttN0pBanJoSUZWSW1RQXlRCkUydFJ3V1NZUTBuVFF0aC9GUEcw
|
|
||||||
bUdhNjJWTkoyL1FUVi9Dc1dxUDBkM0UKLS0tIE1sQXkwcWdGaEFuY0RHQTVXM0J6
|
|
||||||
dWpJcThEbW15V3dXYXpPZklBdW1Hd1kKoIAdmGNPrEctV8h1w8KuvQ5S+BGmgqN9
|
|
||||||
MgpNmUhJjWhgcQpb5BRYpQesBOgU5TBGK7j58A6DMDKlSiYZsdQchQ==
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
|
||||||
lastmodified: "2022-02-03T16:03:17Z"
|
|
||||||
mac: ENC[AES256_GCM,data:AHdYSawajwgAFwlmDN1IPNmT9vWaYKzyVIra2d6sPcjTbZ8/p+VRSRpVm4XZFFsaNnW5AUJaouwXnKYDTmJDXKlr/rQcu9kXqsssQgdzcXaA6l5uJlgsnml8ba7J3OK+iEKMax23mwQEx2EUskCd9ENOwFDkunP02sxqDNOz20k=,iv:8F5OamHt3fAVorf6p+SoIrWoqkcATSGWVoM0EK87S4M=,tag:E1mxXnc7wWkEX5BxhpLtng==,type:str]
|
|
||||||
pgp: []
|
|
||||||
encrypted_regex: ^(data|stringData)$
|
|
||||||
version: 3.7.1
|
|
||||||
`,
|
|
||||||
expected: `apiVersion: v1
|
|
||||||
data:
|
|
||||||
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: secret
|
|
||||||
type: kubernetes.io/dockerconfigjson
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -142,7 +103,7 @@ type: kubernetes.io/dockerconfigjson
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource := &resource.Resource{RNode: *r}
|
resource := &resource.Resource{RNode: *r}
|
||||||
err = maskSopsData(resource)
|
err = trimSopsData(resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to trim sops data: %v", err)
|
t.Fatalf("unable to trim sops data: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import (
|
|||||||
"github.com/gonvenience/bunt"
|
"github.com/gonvenience/bunt"
|
||||||
"github.com/gonvenience/ytbx"
|
"github.com/gonvenience/ytbx"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/homeport/dyff/pkg/dyff"
|
"github.com/homeport/dyff/pkg/dyff"
|
||||||
"github.com/lucasb-eyer/go-colorful"
|
"github.com/lucasb-eyer/go-colorful"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
@@ -52,32 +51,30 @@ func (b *Builder) Manager() (*ssa.ResourceManager, error) {
|
|||||||
return ssa.NewResourceManager(b.client, statusPoller, owner), nil
|
return ssa.NewResourceManager(b.client, statusPoller, owner), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) Diff() (string, bool, error) {
|
func (b *Builder) Diff() (string, error) {
|
||||||
output := strings.Builder{}
|
output := strings.Builder{}
|
||||||
createdOrDrifted := false
|
|
||||||
res, err := b.Build()
|
res, err := b.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", err
|
||||||
}
|
}
|
||||||
// convert the build result into Kubernetes unstructured objects
|
// convert the build result into Kubernetes unstructured objects
|
||||||
objects, err := ssa.ReadObjects(bytes.NewReader(res))
|
objects, err := ssa.ReadObjects(bytes.NewReader(res))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceManager, err := b.Manager()
|
resourceManager, err := b.Manager()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := ssa.SetNativeKindsDefaults(objects); err != nil {
|
if err := ssa.SetNativeKindsDefaults(objects); err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var diffErrs error
|
|
||||||
// create an inventory of objects to be reconciled
|
// create an inventory of objects to be reconciled
|
||||||
newInventory := newInventory()
|
newInventory := newInventory()
|
||||||
for _, obj := range objects {
|
for _, obj := range objects {
|
||||||
@@ -88,8 +85,11 @@ func (b *Builder) Diff() (string, bool, error) {
|
|||||||
}
|
}
|
||||||
change, liveObject, mergedObject, err := resourceManager.Diff(ctx, obj, diffOptions)
|
change, liveObject, mergedObject, err := resourceManager.Diff(ctx, obj, diffOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// gather errors and continue, as we want to see all the diffs
|
if b.kustomization.Spec.Force && ssa.IsImmutableError(err) {
|
||||||
diffErrs = multierror.Append(diffErrs, err)
|
output.WriteString(writeString(fmt.Sprintf("► %s created\n", obj.GetName()), bunt.Green))
|
||||||
|
} else {
|
||||||
|
output.WriteString(writeString(fmt.Sprintf("✗ %v\n", err), bunt.Red))
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,34 +101,31 @@ func (b *Builder) Diff() (string, bool, error) {
|
|||||||
|
|
||||||
if change.Action == string(ssa.CreatedAction) {
|
if change.Action == string(ssa.CreatedAction) {
|
||||||
output.WriteString(writeString(fmt.Sprintf("► %s created\n", change.Subject), bunt.Green))
|
output.WriteString(writeString(fmt.Sprintf("► %s created\n", change.Subject), bunt.Green))
|
||||||
createdOrDrifted = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if change.Action == string(ssa.ConfiguredAction) {
|
if change.Action == string(ssa.ConfiguredAction) {
|
||||||
output.WriteString(writeString(fmt.Sprintf("► %s drifted\n", change.Subject), bunt.WhiteSmoke))
|
output.WriteString(writeString(fmt.Sprintf("► %s drifted\n", change.Subject), bunt.WhiteSmoke))
|
||||||
liveFile, mergedFile, tmpDir, err := writeYamls(liveObject, mergedObject)
|
liveFile, mergedFile, tmpDir, err := writeYamls(liveObject, mergedObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", err
|
||||||
}
|
}
|
||||||
defer cleanupDir(tmpDir)
|
defer cleanupDir(tmpDir)
|
||||||
|
|
||||||
err = diff(liveFile, mergedFile, &output)
|
err = diff(liveFile, mergedFile, &output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
createdOrDrifted = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addObjectsToInventory(newInventory, change)
|
addObjectsToInventory(newInventory, change)
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.kustomization.Spec.Prune && diffErrs == nil {
|
if b.kustomization.Spec.Prune {
|
||||||
oldStatus := b.kustomization.Status.DeepCopy()
|
oldStatus := b.kustomization.Status.DeepCopy()
|
||||||
if oldStatus.Inventory != nil {
|
if oldStatus.Inventory != nil {
|
||||||
diffObjects, err := diffInventory(oldStatus.Inventory, newInventory)
|
diffObjects, err := diffInventory(oldStatus.Inventory, newInventory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", err
|
||||||
}
|
}
|
||||||
for _, object := range diffObjects {
|
for _, object := range diffObjects {
|
||||||
output.WriteString(writeString(fmt.Sprintf("► %s deleted\n", ssa.FmtUnstructured(object)), bunt.OrangeRed))
|
output.WriteString(writeString(fmt.Sprintf("► %s deleted\n", ssa.FmtUnstructured(object)), bunt.OrangeRed))
|
||||||
@@ -136,7 +133,7 @@ func (b *Builder) Diff() (string, bool, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.String(), createdOrDrifted, diffErrs
|
return output.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeYamls(liveObject, mergedObject *unstructured.Unstructured) (string, string, string, error) {
|
func writeYamls(liveObject, mergedObject *unstructured.Unstructured) (string, string, string, error) {
|
||||||
@@ -199,31 +196,17 @@ func diff(liveFile, mergedFile string, output io.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func diffSopsSecret(obj, liveObject, mergedObject *unstructured.Unstructured, change *ssa.ChangeSetEntry) {
|
func diffSopsSecret(obj, liveObject, mergedObject *unstructured.Unstructured, change *ssa.ChangeSetEntry) {
|
||||||
// get both data and stringdata maps
|
data := obj.Object["data"]
|
||||||
data := obj.Object[dataField]
|
for _, v := range data.(map[string]interface{}) {
|
||||||
stringData := obj.Object[stringDataField]
|
|
||||||
|
|
||||||
if m, ok := data.(map[string]interface{}); ok && m != nil {
|
|
||||||
applySopsDiff(m, liveObject, mergedObject, change)
|
|
||||||
}
|
|
||||||
|
|
||||||
if m, ok := stringData.(map[string]interface{}); ok && m != nil {
|
|
||||||
applySopsDiff(m, liveObject, mergedObject, change)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func applySopsDiff(data map[string]interface{}, liveObject, mergedObject *unstructured.Unstructured, change *ssa.ChangeSetEntry) {
|
|
||||||
for _, v := range data {
|
|
||||||
v, err := base64.StdEncoding.DecodeString(v.(string))
|
v, err := base64.StdEncoding.DecodeString(v.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Contains(v, []byte(mask)) {
|
if bytes.Contains(v, []byte(mask)) {
|
||||||
if liveObject != nil && mergedObject != nil {
|
if liveObject != nil && mergedObject != nil {
|
||||||
change.Action = string(ssa.UnchangedAction)
|
change.Action = string(ssa.UnchangedAction)
|
||||||
dataLive := liveObject.Object[dataField].(map[string]interface{})
|
dataLive := liveObject.Object["data"].(map[string]interface{})
|
||||||
dataMerged := mergedObject.Object[dataField].(map[string]interface{})
|
dataMerged := mergedObject.Object["data"].(map[string]interface{})
|
||||||
if cmp.Diff(keys(dataLive), keys(dataMerged)) != "" {
|
if cmp.Diff(keys(dataLive), keys(dataMerged)) != "" {
|
||||||
change.Action = string(ssa.ConfiguredAction)
|
change.Action = string(ssa.ConfiguredAction)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fluxcd/pkg/ssa"
|
"github.com/fluxcd/pkg/ssa"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
@@ -38,12 +37,31 @@ import (
|
|||||||
// Apply is the equivalent of 'kubectl apply --server-side -f'.
|
// Apply is the equivalent of 'kubectl apply --server-side -f'.
|
||||||
// If the given manifest is a kustomization.yaml, then apply performs the equivalent of 'kubectl apply --server-side -k'.
|
// If the given manifest is a kustomization.yaml, then apply performs the equivalent of 'kubectl apply --server-side -k'.
|
||||||
func Apply(ctx context.Context, rcg genericclioptions.RESTClientGetter, manifestPath string) (string, error) {
|
func Apply(ctx context.Context, rcg genericclioptions.RESTClientGetter, manifestPath string) (string, error) {
|
||||||
|
cfg, err := KubeConfig(rcg)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
restMapper, err := rcg.ToRESTMapper()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
kubeClient, err := client.New(cfg, client.Options{Mapper: restMapper})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
kubePoller := polling.NewStatusPoller(kubeClient, restMapper, nil)
|
||||||
|
|
||||||
|
resourceManager := ssa.NewResourceManager(kubeClient, kubePoller, ssa.Owner{
|
||||||
|
Field: "flux",
|
||||||
|
Group: "fluxcd.io",
|
||||||
|
})
|
||||||
|
|
||||||
objs, err := readObjects(manifestPath)
|
objs, err := readObjects(manifestPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(objs) == 0 {
|
if len(objs) < 1 {
|
||||||
return "", fmt.Errorf("no Kubernetes objects found at: %s", manifestPath)
|
return "", fmt.Errorf("no Kubernetes objects found at: %s", manifestPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,42 +69,11 @@ func Apply(ctx context.Context, rcg genericclioptions.RESTClientGetter, manifest
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
changeSet := ssa.NewChangeSet()
|
changeSet, err := resourceManager.ApplyAllStaged(ctx, objs, ssa.DefaultApplyOptions())
|
||||||
|
if err != nil {
|
||||||
// contains only CRDs and Namespaces
|
|
||||||
var stageOne []*unstructured.Unstructured
|
|
||||||
|
|
||||||
// contains all objects except for CRDs and Namespaces
|
|
||||||
var stageTwo []*unstructured.Unstructured
|
|
||||||
|
|
||||||
for _, u := range objs {
|
|
||||||
if ssa.IsClusterDefinition(u) {
|
|
||||||
stageOne = append(stageOne, u)
|
|
||||||
} else {
|
|
||||||
stageTwo = append(stageTwo, u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(stageOne) > 0 {
|
|
||||||
cs, err := applySet(ctx, rcg, stageOne)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
changeSet.Append(cs.Entries)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := waitForSet(rcg, changeSet); err != nil {
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(stageTwo) > 0 {
|
|
||||||
cs, err := applySet(ctx, rcg, stageTwo)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
changeSet.Append(cs.Entries)
|
|
||||||
}
|
|
||||||
|
|
||||||
return changeSet.String(), nil
|
return changeSet.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,42 +98,3 @@ func readObjects(manifestPath string) ([]*unstructured.Unstructured, error) {
|
|||||||
|
|
||||||
return ssa.ReadObjects(bufio.NewReader(ms))
|
return ssa.ReadObjects(bufio.NewReader(ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newManager(rcg genericclioptions.RESTClientGetter) (*ssa.ResourceManager, error) {
|
|
||||||
cfg, err := KubeConfig(rcg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
restMapper, err := rcg.ToRESTMapper()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
kubeClient, err := client.New(cfg, client.Options{Mapper: restMapper, Scheme: NewScheme()})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
kubePoller := polling.NewStatusPoller(kubeClient, restMapper, nil)
|
|
||||||
|
|
||||||
return ssa.NewResourceManager(kubeClient, kubePoller, ssa.Owner{
|
|
||||||
Field: "flux",
|
|
||||||
Group: "fluxcd.io",
|
|
||||||
}), nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func applySet(ctx context.Context, rcg genericclioptions.RESTClientGetter, objects []*unstructured.Unstructured) (*ssa.ChangeSet, error) {
|
|
||||||
man, err := newManager(rcg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return man.ApplyAll(ctx, objects, ssa.DefaultApplyOptions())
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitForSet(rcg genericclioptions.RESTClientGetter, changeSet *ssa.ChangeSet) error {
|
|
||||||
man, err := newManager(rcg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return man.WaitForSet(changeSet.ToObjMetadataSet(), ssa.WaitOptions{Interval: 2 * time.Second, Timeout: time.Minute})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.20.2/kustomize-controller.crds.yaml
|
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.20.0/kustomize-controller.crds.yaml
|
||||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.20.2/kustomize-controller.deployment.yaml
|
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.20.0/kustomize-controller.deployment.yaml
|
||||||
- account.yaml
|
- account.yaml
|
||||||
patchesJson6902:
|
patchesJson6902:
|
||||||
- target:
|
- target:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
- https://github.com/fluxcd/source-controller/releases/download/v0.21.2/source-controller.crds.yaml
|
- https://github.com/fluxcd/source-controller/releases/download/v0.21.1/source-controller.crds.yaml
|
||||||
- https://github.com/fluxcd/source-controller/releases/download/v0.21.2/source-controller.deployment.yaml
|
- https://github.com/fluxcd/source-controller/releases/download/v0.21.1/source-controller.deployment.yaml
|
||||||
- account.yaml
|
- account.yaml
|
||||||
patchesJson6902:
|
patchesJson6902:
|
||||||
- target:
|
- target:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
- https://github.com/fluxcd/source-controller/releases/download/v0.21.2/source-controller.crds.yaml
|
- https://github.com/fluxcd/source-controller/releases/download/v0.21.1/source-controller.crds.yaml
|
||||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.20.2/kustomize-controller.crds.yaml
|
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.20.0/kustomize-controller.crds.yaml
|
||||||
- https://github.com/fluxcd/helm-controller/releases/download/v0.16.0/helm-controller.crds.yaml
|
- https://github.com/fluxcd/helm-controller/releases/download/v0.16.0/helm-controller.crds.yaml
|
||||||
- https://github.com/fluxcd/notification-controller/releases/download/v0.21.0/notification-controller.crds.yaml
|
- https://github.com/fluxcd/notification-controller/releases/download/v0.21.0/notification-controller.crds.yaml
|
||||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.16.0/image-reflector-controller.crds.yaml
|
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.16.0/image-reflector-controller.crds.yaml
|
||||||
|
|||||||
181
rfcs/0002-source-acl/README.md
Normal file
181
rfcs/0002-source-acl/README.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
# RFC-0002 Access control for source references
|
||||||
|
|
||||||
|
**Status:** provisional
|
||||||
|
|
||||||
|
**Creation date:** 2021-11-16
|
||||||
|
|
||||||
|
**Last update:** 2022-02-03
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Cross-namespace references to Flux sources should be subject to
|
||||||
|
Access Control Lists (ACLs) as defined by the owner of a particular source.
|
||||||
|
|
||||||
|
Similar to [Kubernetes Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/),
|
||||||
|
Flux ACLs define policies for restricting the access to the source artifact server based on the
|
||||||
|
caller's namespace.
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
As of [version 0.26](https://github.com/fluxcd/flux2/releases/tag/v0.26.0) (Feb 2022),
|
||||||
|
Flux allows for `Kustomizations`, `HelmReleases` and `ImageUpdateAutomations` to reference sources in different namespaces.
|
||||||
|
On multi-tenant clusters, platform admins can disable this behaviour with the `--no-cross-namespace-refs` flag
|
||||||
|
as described in the [multi-tenancy lockdown documentation](https://fluxcd.io/docs/installation/#multi-tenancy-lockdown).
|
||||||
|
|
||||||
|
This proposal tries to solve the "cross-namespace references side-step namespace isolation" issue (explained in
|
||||||
|
[RFC-0001](https://github.com/fluxcd/flux2/tree/main/rfcs/0001-authorization#cross-namespace-references-side-step-namespace-isolation))
|
||||||
|
for when platform admins want to allow tenants to share sources.
|
||||||
|
|
||||||
|
### Goals
|
||||||
|
|
||||||
|
- Allow source owners to choose which sources are shared and with which namespaces.
|
||||||
|
- Allow cluster admins to enforce source ACLs.
|
||||||
|
|
||||||
|
### Non-Goals
|
||||||
|
|
||||||
|
- Enforce source ACLs by default.
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
|
||||||
|
Extend the current Image Policy/Repository ACL implementation to all the others Flux resources
|
||||||
|
as described in [flux2#1704](https://github.com/fluxcd/flux2/issues/1704).
|
||||||
|
|
||||||
|
When a Flux resource (`Kustomization`, `HelmRelease` or `ImageUpdateAutomation`)
|
||||||
|
refers to a source (`GitRepository`, `HelmRepository` or `Bucket`) in a different namespace,
|
||||||
|
access is granted based on the source ACL.
|
||||||
|
|
||||||
|
The ACL check is performed only if `--enable-source-acl` flag is set to `true` for the following controllers:
|
||||||
|
|
||||||
|
- kustomize-controller
|
||||||
|
- helm-controller
|
||||||
|
- image-automation-controller
|
||||||
|
|
||||||
|
### User Stories
|
||||||
|
|
||||||
|
#### Story 1
|
||||||
|
|
||||||
|
> As a cluster admin, I want to share Helm Repositories approved by the platform team with all tenants.
|
||||||
|
|
||||||
|
If the owner of a Flux `HelmRepository` wants to grant access to the repository for all namespaces in a cluster,
|
||||||
|
an empty `matchLabels` can be used:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: HelmRepository
|
||||||
|
metadata:
|
||||||
|
name: bitnami
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
url: https://charts.bitnami.com/bitnami
|
||||||
|
accessFrom:
|
||||||
|
namespaceSelectors:
|
||||||
|
- matchLabels: {}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the `accessFrom` field is not present and `--enable-source-acl` is set to `true`,
|
||||||
|
means that a source can't be accessed from any other namespace but the one where it currently resides.
|
||||||
|
|
||||||
|
#### Story 2
|
||||||
|
|
||||||
|
> As a tenant, I want to share my app repository with another tenant
|
||||||
|
> so that they can deploy the application in their own namespace.
|
||||||
|
|
||||||
|
If `dev-team1` wants to grant read access to their repository to `dev-team2`,
|
||||||
|
a `matchLabels` that selects the namespace owned by `dev-team2` can be used:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
name: app1
|
||||||
|
namespace: dev-team1
|
||||||
|
spec:
|
||||||
|
url: ssh://git@github.com/<org>/app1-deploy
|
||||||
|
secretRef:
|
||||||
|
name: app1-ro-ssh-key
|
||||||
|
accessFrom:
|
||||||
|
namespaceSelectors:
|
||||||
|
- matchLabels:
|
||||||
|
kubernetes.io/metadata.name: dev-team2
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Story 3
|
||||||
|
|
||||||
|
> As a cluster admin, I want to let tenants configure image automation in their namespaces by
|
||||||
|
> referring to a Git repository managed by the platform team.
|
||||||
|
|
||||||
|
If the owner of a Flux `GitRepository` wants to grant write access to `ImageUpdateAutomations` in a different namespace,
|
||||||
|
a `matchLabels` that selects the image automation namespace can be used:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
name: cluster-config
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
url: ssh://git@github.com/<org>/cluster-config
|
||||||
|
secretRef:
|
||||||
|
name: read-write-ssh-key
|
||||||
|
accessFrom:
|
||||||
|
namespaceSelectors:
|
||||||
|
- matchLabels:
|
||||||
|
kubernetes.io/metadata.name: dev-team1
|
||||||
|
```
|
||||||
|
|
||||||
|
The `dev-team1` can refer to the `cluster-config` repository in their image automation config:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: image.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: ImageUpdateAutomation
|
||||||
|
metadata:
|
||||||
|
name: app1
|
||||||
|
namespace: dev-team1
|
||||||
|
spec:
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: cluster-config
|
||||||
|
namespace: flux-system
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alternatives
|
||||||
|
|
||||||
|
#### Admission controllers
|
||||||
|
|
||||||
|
An alternative solution to source ACLs is to use an admission controller such as Kyverno or OPA Gatekeeper
|
||||||
|
and allow/disallow cross-namespace access to specific source.
|
||||||
|
|
||||||
|
The current proposal offers the same feature but without the need to manage yet another controller to guard
|
||||||
|
sources.
|
||||||
|
|
||||||
|
#### Kubernetes RBAC
|
||||||
|
|
||||||
|
Another alternative is to rely on impersonation and create a `ClusterRoleBinding` per named source and tenant account
|
||||||
|
as described in [fluxcd/flux2#582](https://github.com/fluxcd/flux2/pull/582).
|
||||||
|
|
||||||
|
The current proposal is more flexible than RBAC and implies less work for Flux users. ALCs act more like
|
||||||
|
Kubernetes Network Policies where access is defined based on labels, with RBAC every time a namespace is added,
|
||||||
|
the platform admins have to create new RBAC rules to target that namespace.
|
||||||
|
|
||||||
|
#### Source reflection CRD
|
||||||
|
|
||||||
|
Yet another alternative is to introduce a new API kind `SourceReflection` as described in
|
||||||
|
[fluxcd/flux2#582-821027543](https://github.com/fluxcd/flux2/pull/582#issuecomment-821027543).
|
||||||
|
|
||||||
|
The current proposal allows the owner to define the access control list on the source object, instead
|
||||||
|
of creating objects in namespaces where it has no control over.
|
||||||
|
|
||||||
|
#### Remove cross-namespace refs
|
||||||
|
|
||||||
|
An alternative is to simply remove cross-namespace references from the Flux API.
|
||||||
|
|
||||||
|
This would break with current behavior, and users would have to make substantial changes to their
|
||||||
|
repository structure and workflow. In cases where e.g. a resource is common (across many namespaces),
|
||||||
|
this would mean the source-controller would use way more memory and network bandwidth that grows with
|
||||||
|
each namespace that uses the same Git or Helm repository due to the requirement of having to duplicate
|
||||||
|
"common" resources.
|
||||||
|
|
||||||
|
## Implementation History
|
||||||
|
|
||||||
|
- ACL support for allowing cross-namespace access to `ImageRepositories` was first released in flux2 **v0.23.0**.
|
||||||
|
- Disabling cross-namespace access to sources was first released in flux2 **v0.26.0**.
|
||||||
@@ -483,7 +483,7 @@ func TestImageRepositoryACR(t *testing.T) {
|
|||||||
Interval: metav1.Duration{
|
Interval: metav1.Duration{
|
||||||
Duration: 1 * time.Minute,
|
Duration: 1 * time.Minute,
|
||||||
},
|
},
|
||||||
SourceRef: automationv1beta1.CrossNamespaceSourceReference{
|
SourceRef: automationv1beta1.SourceReference{
|
||||||
Kind: "GitRepository",
|
Kind: "GitRepository",
|
||||||
Name: name,
|
Name: name,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ require (
|
|||||||
github.com/fluxcd/helm-controller/api v0.16.0
|
github.com/fluxcd/helm-controller/api v0.16.0
|
||||||
github.com/fluxcd/image-automation-controller/api v0.20.0
|
github.com/fluxcd/image-automation-controller/api v0.20.0
|
||||||
github.com/fluxcd/image-reflector-controller/api v0.16.0
|
github.com/fluxcd/image-reflector-controller/api v0.16.0
|
||||||
github.com/fluxcd/kustomize-controller/api v0.20.2
|
github.com/fluxcd/kustomize-controller/api v0.20.0
|
||||||
github.com/fluxcd/notification-controller/api v0.21.0
|
github.com/fluxcd/notification-controller/api v0.21.0
|
||||||
github.com/fluxcd/pkg/apis/meta v0.10.2
|
github.com/fluxcd/pkg/apis/meta v0.10.2
|
||||||
github.com/fluxcd/pkg/runtime v0.12.4
|
github.com/fluxcd/pkg/runtime v0.12.4
|
||||||
github.com/fluxcd/source-controller/api v0.21.2
|
github.com/fluxcd/source-controller/api v0.21.1
|
||||||
github.com/hashicorp/terraform-exec v0.14.0
|
github.com/hashicorp/terraform-exec v0.14.0
|
||||||
github.com/libgit2/git2go/v31 v31.6.1
|
github.com/libgit2/git2go/v31 v31.6.1
|
||||||
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
|
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
|
||||||
|
|||||||
@@ -204,8 +204,8 @@ github.com/fluxcd/image-automation-controller/api v0.20.0 h1:Z+lxqif0KwccsuNOBZq
|
|||||||
github.com/fluxcd/image-automation-controller/api v0.20.0/go.mod h1:XhLYccGUbmJvTTpJ1jAFKZHr2e1GNXy0T85ZBO50mik=
|
github.com/fluxcd/image-automation-controller/api v0.20.0/go.mod h1:XhLYccGUbmJvTTpJ1jAFKZHr2e1GNXy0T85ZBO50mik=
|
||||||
github.com/fluxcd/image-reflector-controller/api v0.16.0 h1:1O1YdoK7LsJgWLyvfZTSbvQcUQCBcgJ573HA0arlQQY=
|
github.com/fluxcd/image-reflector-controller/api v0.16.0 h1:1O1YdoK7LsJgWLyvfZTSbvQcUQCBcgJ573HA0arlQQY=
|
||||||
github.com/fluxcd/image-reflector-controller/api v0.16.0/go.mod h1:OIe3mSXc3OwQiNbiQ9vNXWYtNif31hc7WAbZWlFUUnc=
|
github.com/fluxcd/image-reflector-controller/api v0.16.0/go.mod h1:OIe3mSXc3OwQiNbiQ9vNXWYtNif31hc7WAbZWlFUUnc=
|
||||||
github.com/fluxcd/kustomize-controller/api v0.20.2 h1:zqCvKGsNCL10WMfmjk2Sd526J6gv8ml027DwesFoZsc=
|
github.com/fluxcd/kustomize-controller/api v0.20.0 h1:Vw+2qCxeHMv0y1mfiBgVrMfcfFevBMrRfLEdfPTrb40=
|
||||||
github.com/fluxcd/kustomize-controller/api v0.20.2/go.mod h1:5MdpzJVx8+KiDIRv37zLme992BAOCgE0v1n+NOgs1lo=
|
github.com/fluxcd/kustomize-controller/api v0.20.0/go.mod h1:5MdpzJVx8+KiDIRv37zLme992BAOCgE0v1n+NOgs1lo=
|
||||||
github.com/fluxcd/notification-controller/api v0.21.0 h1:D5B3TH5YtSww0SyvW1Ru5xWsh0MgHQanC/a1t3CvXq0=
|
github.com/fluxcd/notification-controller/api v0.21.0 h1:D5B3TH5YtSww0SyvW1Ru5xWsh0MgHQanC/a1t3CvXq0=
|
||||||
github.com/fluxcd/notification-controller/api v0.21.0/go.mod h1:gA9/j0kjh7VDuUC2Cubr9twxOdzb/0+ojcE9Lzsc9ug=
|
github.com/fluxcd/notification-controller/api v0.21.0/go.mod h1:gA9/j0kjh7VDuUC2Cubr9twxOdzb/0+ojcE9Lzsc9ug=
|
||||||
github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc=
|
github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc=
|
||||||
@@ -218,8 +218,8 @@ github.com/fluxcd/pkg/runtime v0.12.3/go.mod h1:imJ2xYy/d4PbSinX2IefmZk+iS2c1P5f
|
|||||||
github.com/fluxcd/pkg/runtime v0.12.4 h1:gA27RG/+adN2/7Qe03PB46Iwmye/MusPCpuS4zQ2fW0=
|
github.com/fluxcd/pkg/runtime v0.12.4 h1:gA27RG/+adN2/7Qe03PB46Iwmye/MusPCpuS4zQ2fW0=
|
||||||
github.com/fluxcd/pkg/runtime v0.12.4/go.mod h1:gspNvhAqodZgSmK1ZhMtvARBf/NGAlxmaZaIOHkJYsc=
|
github.com/fluxcd/pkg/runtime v0.12.4/go.mod h1:gspNvhAqodZgSmK1ZhMtvARBf/NGAlxmaZaIOHkJYsc=
|
||||||
github.com/fluxcd/source-controller/api v0.21.0/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
github.com/fluxcd/source-controller/api v0.21.0/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
||||||
github.com/fluxcd/source-controller/api v0.21.2 h1:J0S5NN4V8FPLrkSMXIUoUvj1X/RuTpVJSjIRF414wmc=
|
github.com/fluxcd/source-controller/api v0.21.1 h1:7X39YQHmB1vmIBrHxU+YAqxwtdC9Zh+tdtMKREW3xiQ=
|
||||||
github.com/fluxcd/source-controller/api v0.21.2/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
github.com/fluxcd/source-controller/api v0.21.1/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
||||||
|
|||||||
Reference in New Issue
Block a user