Merge branch 'main' into patch-3
This commit is contained in:
@@ -27,8 +27,9 @@ import (
|
||||
"time"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
|
||||
"github.com/fluxcd/flux2/pkg/manifestgen"
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||
)
|
||||
|
||||
// Generate returns the install manifests as a multi-doc YAML.
|
||||
@@ -54,7 +55,7 @@ func Generate(options Options, manifestsBase string) (*manifestgen.Manifest, err
|
||||
} else {
|
||||
// download the manifests base from GitHub
|
||||
if manifestsBase == "" {
|
||||
manifestsBase, err = os.MkdirTemp("", options.Namespace)
|
||||
manifestsBase, err = manifestgen.MkdirTempAbs("", options.Namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("temp dir error: %w", err)
|
||||
}
|
||||
@@ -91,7 +92,7 @@ func Generate(options Options, manifestsBase string) (*manifestgen.Manifest, err
|
||||
// GetLatestVersion calls the GitHub API and returns the latest released version.
|
||||
func GetLatestVersion() (string, error) {
|
||||
ghURL := "https://api.github.com/repos/fluxcd/flux2/releases/latest"
|
||||
c := http.DefaultClient
|
||||
c := cleanhttp.DefaultClient()
|
||||
c.Timeout = 15 * time.Second
|
||||
|
||||
res, err := c.Get(ghURL)
|
||||
@@ -121,7 +122,7 @@ func ExistingVersion(version string) (bool, error) {
|
||||
}
|
||||
|
||||
ghURL := fmt.Sprintf("https://api.github.com/repos/fluxcd/flux2/releases/tags/%s", version)
|
||||
c := http.DefaultClient
|
||||
c := cleanhttp.DefaultClient()
|
||||
c.Timeout = 15 * time.Second
|
||||
|
||||
res, err := c.Get(ghURL)
|
||||
|
||||
@@ -26,10 +26,12 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/pkg/untar"
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
|
||||
"github.com/fluxcd/flux2/pkg/manifestgen/kustomization"
|
||||
"github.com/fluxcd/pkg/kustomize/filesys"
|
||||
"github.com/fluxcd/pkg/tar"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen/kustomization"
|
||||
)
|
||||
|
||||
func fetch(ctx context.Context, url, version, dir string) error {
|
||||
@@ -44,7 +46,7 @@ func fetch(ctx context.Context, url, version, dir string) error {
|
||||
}
|
||||
|
||||
// download
|
||||
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
||||
resp, err := cleanhttp.DefaultClient().Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download manifests.tar.gz from %s, error: %w", ghURL, err)
|
||||
}
|
||||
@@ -56,7 +58,7 @@ func fetch(ctx context.Context, url, version, dir string) error {
|
||||
}
|
||||
|
||||
// extract
|
||||
if _, err = untar.Untar(resp.Body, dir); err != nil {
|
||||
if err = tar.Untar(resp.Body, dir, tar.WithMaxUntarSize(-1)); err != nil {
|
||||
return fmt.Errorf("failed to untar manifests.tar.gz from %s, error: %w", ghURL, err)
|
||||
}
|
||||
|
||||
@@ -71,9 +73,9 @@ func generate(base string, options Options) error {
|
||||
// In such environments they normally add `.cluster.local` and `.local`
|
||||
// suffixes to `no_proxy` variable in order to prevent cluster-local
|
||||
// traffic from going through http proxy. Without fully specified
|
||||
// domain they need to mention `notifications-controller` explicity in
|
||||
// domain they need to mention `notifications-controller` explicitly in
|
||||
// `no_proxy` variable after debugging http proxy logs.
|
||||
options.EventsAddr = fmt.Sprintf("http://%s.%s.svc.%s/", options.NotificationController, options.Namespace, options.ClusterDomain)
|
||||
options.EventsAddr = fmt.Sprintf("http://%s.%s.svc.%s./", options.NotificationController, options.Namespace, options.ClusterDomain)
|
||||
}
|
||||
|
||||
if err := execTemplate(options, namespaceTmpl, path.Join(base, "namespace.yaml")); err != nil {
|
||||
@@ -126,8 +128,12 @@ func build(base, output string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fs := filesys.MakeFsOnDisk()
|
||||
if err := fs.WriteFile(output, resources); err != nil {
|
||||
outputBase := filepath.Dir(strings.TrimSuffix(output, string(filepath.Separator)))
|
||||
fs, err := filesys.MakeFsOnDiskSecure(outputBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = fs.WriteFile(output, resources); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,6 @@ patches:
|
||||
- path: node-selector.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
|
||||
patchesJson6902:
|
||||
{{- range $i, $component := .Components }}
|
||||
{{- if eq $component "notification-controller" }}
|
||||
- target:
|
||||
@@ -165,6 +163,9 @@ apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{.Namespace}}
|
||||
labels:
|
||||
pod-security.kubernetes.io/warn: restricted
|
||||
pod-security.kubernetes.io/warn-version: latest
|
||||
`
|
||||
|
||||
func execTemplate(obj interface{}, tmpl, filename string) error {
|
||||
|
||||
@@ -20,20 +20,23 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/krusty"
|
||||
"sigs.k8s.io/kustomize/api/provider"
|
||||
kustypes "sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/fluxcd/flux2/pkg/manifestgen"
|
||||
"github.com/fluxcd/pkg/kustomize/filesys"
|
||||
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||
)
|
||||
|
||||
// Generate scans the given directory for Kubernetes manifests and creates a kustomization.yaml
|
||||
// including all discovered manifests as resources.
|
||||
// Generate scans the given directory for Kubernetes manifests and creates a
|
||||
// konfig.DefaultKustomizationFileName file, including all discovered manifests
|
||||
// as resources.
|
||||
func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
kfile := filepath.Join(options.TargetPath, konfig.DefaultKustomizationFileName())
|
||||
abskfile := filepath.Join(options.BaseDir, kfile)
|
||||
@@ -50,7 +53,7 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
return nil
|
||||
}
|
||||
if info.IsDir() {
|
||||
// If a sub-directory contains an existing Kustomization file add the
|
||||
// If a sub-directory contains an existing Kustomization file, add the
|
||||
// directory as a resource and do not decent into it.
|
||||
for _, kfilename := range konfig.RecognizedKustomizationFileNames() {
|
||||
if options.FileSystem.Exists(filepath.Join(path, kfilename)) {
|
||||
@@ -88,7 +91,9 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Close()
|
||||
if err = f.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kus := kustypes.Kustomization{
|
||||
TypeMeta: kustypes.TypeMeta{
|
||||
@@ -128,20 +133,40 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// kustomizeBuildMutex is a workaround for a concurrent map read and map write bug.
|
||||
// TODO(stefan): https://github.com/kubernetes-sigs/kustomize/issues/3659
|
||||
var kustomizeBuildMutex sync.Mutex
|
||||
|
||||
// Build takes a Kustomize overlays and returns the resulting manifests as multi-doc YAML.
|
||||
// Build takes the path to a directory with a konfig.RecognizedKustomizationFileNames,
|
||||
// builds it, and returns the resulting manifests as multi-doc YAML. It restricts the
|
||||
// Kustomize file system to the parent directory of the base.
|
||||
func Build(base string) ([]byte, error) {
|
||||
// TODO(stefan): temporary workaround for concurrent map read and map write bug
|
||||
// https://github.com/kubernetes-sigs/kustomize/issues/3659
|
||||
// TODO(hidde): drop this when consumers have moved away to BuildWithRoot.
|
||||
parent := filepath.Dir(strings.TrimSuffix(base, string(filepath.Separator)))
|
||||
return BuildWithRoot(parent, base)
|
||||
}
|
||||
|
||||
// BuildWithRoot takes the path to a directory with a konfig.RecognizedKustomizationFileNames,
|
||||
// builds it, and returns the resulting manifests as multi-doc YAML.
|
||||
// The Kustomize file system is restricted to root.
|
||||
func BuildWithRoot(root, base string) ([]byte, error) {
|
||||
kustomizeBuildMutex.Lock()
|
||||
defer kustomizeBuildMutex.Unlock()
|
||||
|
||||
kfile := filepath.Join(base, konfig.DefaultKustomizationFileName())
|
||||
fs, err := filesys.MakeFsOnDiskSecureBuild(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fs := filesys.MakeFsOnDisk()
|
||||
if !fs.Exists(kfile) {
|
||||
return nil, fmt.Errorf("%s not found", kfile)
|
||||
var kfile string
|
||||
for _, f := range konfig.RecognizedKustomizationFileNames() {
|
||||
if kf := filepath.Join(base, f); fs.Exists(kf) {
|
||||
kfile = kf
|
||||
break
|
||||
}
|
||||
}
|
||||
if kfile == "" {
|
||||
return nil, fmt.Errorf("%s not found", konfig.DefaultKustomizationFileName())
|
||||
}
|
||||
|
||||
// TODO(hidde): work around for a bug in kustomize causing it to
|
||||
@@ -161,11 +186,8 @@ func Build(base string) ([]byte, error) {
|
||||
}
|
||||
|
||||
buildOptions := &krusty.Options{
|
||||
DoLegacyResourceSort: true,
|
||||
LoadRestrictions: kustypes.LoadRestrictionsNone,
|
||||
AddManagedbyLabel: false,
|
||||
DoPrune: false,
|
||||
PluginConfig: kustypes.DisabledPluginConfig(),
|
||||
LoadRestrictions: kustypes.LoadRestrictionsNone,
|
||||
PluginConfig: kustypes.DisabledPluginConfig(),
|
||||
}
|
||||
|
||||
k := krusty.MakeKustomizer(buildOptions)
|
||||
|
||||
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
|
||||
package kustomization
|
||||
|
||||
import "sigs.k8s.io/kustomize/api/filesys"
|
||||
import "sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
|
||||
type Options struct {
|
||||
FileSystem filesys.FileSystem
|
||||
@@ -25,6 +25,8 @@ type Options struct {
|
||||
}
|
||||
|
||||
func MakeDefaultOptions() Options {
|
||||
// TODO(hidde): switch MakeFsOnDisk to MakeFsOnDiskSecureBuild when we
|
||||
// break API.
|
||||
return Options{
|
||||
FileSystem: filesys.MakeFsOnDisk(),
|
||||
BaseDir: "",
|
||||
|
||||
@@ -34,7 +34,7 @@ type Manifest struct {
|
||||
Content string
|
||||
}
|
||||
|
||||
// WriteFile writes the YAML content to a file inside the the root path.
|
||||
// WriteFile writes the YAML content to a file inside the root path.
|
||||
// If the file does not exist, WriteFile creates it with permissions perm,
|
||||
// otherwise WriteFile overwrites the file, without changing permissions.
|
||||
func (m *Manifest) WriteFile(rootDir string) (string, error) {
|
||||
|
||||
@@ -18,6 +18,8 @@ package sourcesecret
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
|
||||
"github.com/fluxcd/pkg/ssh"
|
||||
)
|
||||
|
||||
type PrivateKeyAlgorithm string
|
||||
@@ -31,30 +33,53 @@ const (
|
||||
const (
|
||||
UsernameSecretKey = "username"
|
||||
PasswordSecretKey = "password"
|
||||
CAFileSecretKey = "caFile"
|
||||
CertFileSecretKey = "certFile"
|
||||
KeyFileSecretKey = "keyFile"
|
||||
CACrtSecretKey = "ca.crt"
|
||||
TLSCrtSecretKey = "tls.crt"
|
||||
TLSKeySecretKey = "tls.key"
|
||||
PrivateKeySecretKey = "identity"
|
||||
PublicKeySecretKey = "identity.pub"
|
||||
KnownHostsSecretKey = "known_hosts"
|
||||
BearerTokenKey = "bearerToken"
|
||||
|
||||
// Deprecated: Replaced by CACrtSecretKey, but kept for backwards
|
||||
// compatibility with deprecated TLS flags.
|
||||
CAFileSecretKey = "caFile"
|
||||
// Deprecated: Replaced by TLSCrtSecretKey, but kept for backwards
|
||||
// compatibility with deprecated TLS flags.
|
||||
CertFileSecretKey = "certFile"
|
||||
// Deprecated: Replaced by TLSKeySecretKey, but kept for backwards
|
||||
// compatibility with deprecated TLS flags.
|
||||
KeyFileSecretKey = "keyFile"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Labels map[string]string
|
||||
Registry string
|
||||
SSHHostname string
|
||||
PrivateKeyAlgorithm PrivateKeyAlgorithm
|
||||
RSAKeyBits int
|
||||
ECDSACurve elliptic.Curve
|
||||
PrivateKeyPath string
|
||||
Keypair *ssh.KeyPair
|
||||
Username string
|
||||
Password string
|
||||
CAFilePath string
|
||||
CertFilePath string
|
||||
KeyFilePath string
|
||||
CACrt []byte
|
||||
TLSCrt []byte
|
||||
TLSKey []byte
|
||||
TargetPath string
|
||||
ManifestFile string
|
||||
BearerToken string
|
||||
|
||||
// Deprecated: Replaced by CACrt, but kept for backwards compatibility
|
||||
// with deprecated TLS flags.
|
||||
CAFile []byte
|
||||
// Deprecated: Replaced by TLSCrt, but kept for backwards compatibility
|
||||
// with deprecated TLS flags.
|
||||
CertFile []byte
|
||||
// Deprecated: Replaced by TLSKey, but kept for backwards compatibility
|
||||
// with deprecated TLS flags.
|
||||
KeyFile []byte
|
||||
}
|
||||
|
||||
func MakeDefaultOptions() Options {
|
||||
@@ -63,12 +88,12 @@ func MakeDefaultOptions() Options {
|
||||
Namespace: "flux-system",
|
||||
Labels: map[string]string{},
|
||||
PrivateKeyAlgorithm: RSAPrivateKeyAlgorithm,
|
||||
PrivateKeyPath: "",
|
||||
Username: "",
|
||||
Password: "",
|
||||
CAFilePath: "",
|
||||
CertFilePath: "",
|
||||
KeyFilePath: "",
|
||||
CAFile: []byte{},
|
||||
CertFile: []byte{},
|
||||
KeyFile: []byte{},
|
||||
ManifestFile: "secret.yaml",
|
||||
BearerToken: "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package sourcesecret
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
@@ -31,11 +33,32 @@ import (
|
||||
|
||||
"github.com/fluxcd/pkg/ssh"
|
||||
|
||||
"github.com/fluxcd/flux2/pkg/manifestgen"
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||
)
|
||||
|
||||
const defaultSSHPort = 22
|
||||
|
||||
// types gotten from https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/create/create_secret_docker.go#L64-L84
|
||||
|
||||
// DockerConfigJSON represents a local docker auth config file
|
||||
// for pulling images.
|
||||
type DockerConfigJSON struct {
|
||||
Auths DockerConfig `json:"auths"`
|
||||
}
|
||||
|
||||
// DockerConfig represents the config file used by the docker CLI.
|
||||
// This config that represents the credentials that should be used
|
||||
// when pulling images from specific image repositories.
|
||||
type DockerConfig map[string]DockerConfigEntry
|
||||
|
||||
// DockerConfigEntry holds the user information that grant the access to docker registry
|
||||
type DockerConfigEntry struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Auth string `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
var err error
|
||||
|
||||
@@ -43,10 +66,8 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
switch {
|
||||
case options.Username != "" && options.Password != "":
|
||||
// noop
|
||||
case len(options.PrivateKeyPath) > 0:
|
||||
if keypair, err = loadKeyPair(options.PrivateKeyPath, options.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case options.Keypair != nil:
|
||||
keypair = options.Keypair
|
||||
case len(options.PrivateKeyAlgorithm) > 0:
|
||||
if keypair, err = generateKeyPair(options); err != nil {
|
||||
return nil, err
|
||||
@@ -55,29 +76,20 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
|
||||
var hostKey []byte
|
||||
if keypair != nil {
|
||||
if hostKey, err = scanHostKey(options.SSHHostname); err != nil {
|
||||
if hostKey, err = ScanHostKey(options.SSHHostname); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var caFile []byte
|
||||
if options.CAFilePath != "" {
|
||||
if caFile, err = os.ReadFile(options.CAFilePath); err != nil {
|
||||
return nil, fmt.Errorf("failed to read CA file: %w", err)
|
||||
var dockerCfgJson []byte
|
||||
if options.Registry != "" {
|
||||
dockerCfgJson, err = generateDockerConfigJson(options.Registry, options.Username, options.Password)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate json for docker config: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var certFile, keyFile []byte
|
||||
if options.CertFilePath != "" && options.KeyFilePath != "" {
|
||||
if certFile, err = os.ReadFile(options.CertFilePath); err != nil {
|
||||
return nil, fmt.Errorf("failed to read cert file: %w", err)
|
||||
}
|
||||
if keyFile, err = os.ReadFile(options.KeyFilePath); err != nil {
|
||||
return nil, fmt.Errorf("failed to read key file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
secret := buildSecret(keypair, hostKey, caFile, certFile, keyFile, options)
|
||||
secret := buildSecret(keypair, hostKey, dockerCfgJson, options)
|
||||
b, err := yaml.Marshal(secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -89,7 +101,36 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildSecret(keypair *ssh.KeyPair, hostKey, caFile, certFile, keyFile []byte, options Options) (secret corev1.Secret) {
|
||||
func LoadKeyPairFromPath(path, password string) (*ssh.KeyPair, error) {
|
||||
if path == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open private key file: %w", err)
|
||||
}
|
||||
return LoadKeyPair(b, password)
|
||||
}
|
||||
|
||||
func LoadKeyPair(privateKey []byte, password string) (*ssh.KeyPair, error) {
|
||||
var ppk cryptssh.Signer
|
||||
var err error
|
||||
if password != "" {
|
||||
ppk, err = cryptssh.ParsePrivateKeyWithPassphrase(privateKey, []byte(password))
|
||||
} else {
|
||||
ppk, err = cryptssh.ParsePrivateKey(privateKey)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ssh.KeyPair{
|
||||
PublicKey: cryptssh.MarshalAuthorizedKey(ppk.PublicKey()),
|
||||
PrivateKey: privateKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildSecret(keypair *ssh.KeyPair, hostKey, dockerCfg []byte, options Options) (secret corev1.Secret) {
|
||||
secret.TypeMeta = metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Secret",
|
||||
@@ -101,21 +142,36 @@ func buildSecret(keypair *ssh.KeyPair, hostKey, caFile, certFile, keyFile []byte
|
||||
secret.Labels = options.Labels
|
||||
secret.StringData = map[string]string{}
|
||||
|
||||
if dockerCfg != nil {
|
||||
secret.Type = corev1.SecretTypeDockerConfigJson
|
||||
secret.StringData[corev1.DockerConfigJsonKey] = string(dockerCfg)
|
||||
return
|
||||
}
|
||||
|
||||
if options.Username != "" && options.Password != "" {
|
||||
secret.StringData[UsernameSecretKey] = options.Username
|
||||
secret.StringData[PasswordSecretKey] = options.Password
|
||||
}
|
||||
|
||||
if caFile != nil {
|
||||
secret.StringData[CAFileSecretKey] = string(caFile)
|
||||
if options.BearerToken != "" {
|
||||
secret.StringData[BearerTokenKey] = options.BearerToken
|
||||
}
|
||||
|
||||
if certFile != nil && keyFile != nil {
|
||||
secret.StringData[CertFileSecretKey] = string(certFile)
|
||||
secret.StringData[KeyFileSecretKey] = string(keyFile)
|
||||
if len(options.CACrt) != 0 {
|
||||
secret.StringData[CACrtSecretKey] = string(options.CACrt)
|
||||
} else if len(options.CAFile) != 0 {
|
||||
secret.StringData[CAFileSecretKey] = string(options.CAFile)
|
||||
}
|
||||
|
||||
if keypair != nil && hostKey != nil {
|
||||
if len(options.TLSCrt) != 0 && len(options.TLSKey) != 0 {
|
||||
secret.Type = corev1.SecretTypeTLS
|
||||
secret.StringData[TLSCrtSecretKey] = string(options.TLSCrt)
|
||||
secret.StringData[TLSKeySecretKey] = string(options.TLSKey)
|
||||
} else if len(options.CertFile) != 0 && len(options.KeyFile) != 0 {
|
||||
secret.StringData[CertFileSecretKey] = string(options.CertFile)
|
||||
secret.StringData[KeyFileSecretKey] = string(options.KeyFile)
|
||||
}
|
||||
|
||||
if keypair != nil && len(hostKey) != 0 {
|
||||
secret.StringData[PrivateKeySecretKey] = string(keypair.PrivateKey)
|
||||
secret.StringData[PublicKeySecretKey] = string(keypair.PublicKey)
|
||||
secret.StringData[KnownHostsSecretKey] = string(hostKey)
|
||||
@@ -128,29 +184,6 @@ func buildSecret(keypair *ssh.KeyPair, hostKey, caFile, certFile, keyFile []byte
|
||||
return
|
||||
}
|
||||
|
||||
func loadKeyPair(path string, password string) (*ssh.KeyPair, error) {
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open private key file: %w", err)
|
||||
}
|
||||
|
||||
var ppk cryptssh.Signer
|
||||
if password != "" {
|
||||
ppk, err = cryptssh.ParsePrivateKeyWithPassphrase(b, []byte(password))
|
||||
} else {
|
||||
ppk, err = cryptssh.ParsePrivateKey(b)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ssh.KeyPair{
|
||||
PublicKey: cryptssh.MarshalAuthorizedKey(ppk.PublicKey()),
|
||||
PrivateKey: b,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func generateKeyPair(options Options) (*ssh.KeyPair, error) {
|
||||
var keyGen ssh.KeyPairGenerator
|
||||
switch options.PrivateKeyAlgorithm {
|
||||
@@ -170,14 +203,14 @@ func generateKeyPair(options Options) (*ssh.KeyPair, error) {
|
||||
return pair, nil
|
||||
}
|
||||
|
||||
func scanHostKey(host string) ([]byte, error) {
|
||||
func ScanHostKey(host string) ([]byte, error) {
|
||||
if _, _, err := net.SplitHostPort(host); err != nil {
|
||||
// Assume we are dealing with a hostname without a port,
|
||||
// append the default SSH port as this is required for
|
||||
// host key scanning to work.
|
||||
host = fmt.Sprintf("%s:%d", host, defaultSSHPort)
|
||||
}
|
||||
hostKey, err := ssh.ScanHostKey(host, 30*time.Second)
|
||||
hostKey, err := ssh.ScanHostKey(host, 30*time.Second, []string{}, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SSH key scan for host %s failed, error: %w", host, err)
|
||||
}
|
||||
@@ -189,3 +222,19 @@ func resourceToString(data []byte) string {
|
||||
data = bytes.Replace(data, []byte("status: {}\n"), []byte(""), 1)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func generateDockerConfigJson(url, username, password string) ([]byte, error) {
|
||||
cred := fmt.Sprintf("%s:%s", username, password)
|
||||
auth := base64.StdEncoding.EncodeToString([]byte(cred))
|
||||
cfg := DockerConfigJSON{
|
||||
Auths: map[string]DockerConfigEntry{
|
||||
url: {
|
||||
Username: username,
|
||||
Password: password,
|
||||
Auth: auth,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return json.Marshal(cfg)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !e2e
|
||||
// +build !e2e
|
||||
|
||||
/*
|
||||
@@ -47,7 +48,7 @@ func Test_passwordLoadKeyPair(t *testing.T) {
|
||||
pk, _ := os.ReadFile(tt.privateKeyPath)
|
||||
ppk, _ := os.ReadFile(tt.publicKeyPath)
|
||||
|
||||
got, err := loadKeyPair(tt.privateKeyPath, tt.password)
|
||||
got, err := LoadKeyPair(pk, tt.password)
|
||||
if err != nil {
|
||||
t.Errorf("loadKeyPair() error = %v", err)
|
||||
return
|
||||
@@ -66,24 +67,13 @@ func Test_passwordLoadKeyPair(t *testing.T) {
|
||||
func Test_PasswordlessLoadKeyPair(t *testing.T) {
|
||||
for algo, privateKey := range testdata.PEMBytes {
|
||||
t.Run(algo, func(t *testing.T) {
|
||||
f, err := os.CreateTemp("", "test-private-key-")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create temporary file. err: %s", err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
if _, err = f.Write(privateKey); err != nil {
|
||||
t.Fatalf("unable to write private key to file. err: %s", err)
|
||||
}
|
||||
|
||||
got, err := loadKeyPair(f.Name(), "")
|
||||
got, err := LoadKeyPair(privateKey, "")
|
||||
if err != nil {
|
||||
t.Errorf("loadKeyPair() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
pk, _ := os.ReadFile(f.Name())
|
||||
if !reflect.DeepEqual(got.PrivateKey, pk) {
|
||||
if !reflect.DeepEqual(got.PrivateKey, privateKey) {
|
||||
t.Errorf("PrivateKey %s != %s", got.PrivateKey, string(privateKey))
|
||||
}
|
||||
|
||||
|
||||
@@ -32,20 +32,18 @@ type Options struct {
|
||||
Secret string
|
||||
TargetPath string
|
||||
ManifestFile string
|
||||
GitImplementation string
|
||||
RecurseSubmodules bool
|
||||
}
|
||||
|
||||
func MakeDefaultOptions() Options {
|
||||
return Options{
|
||||
Interval: 1 * time.Minute,
|
||||
URL: "",
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Branch: "main",
|
||||
Secret: "flux-system",
|
||||
ManifestFile: "gotk-sync.yaml",
|
||||
TargetPath: "",
|
||||
GitImplementation: "",
|
||||
Interval: 1 * time.Minute,
|
||||
URL: "",
|
||||
Name: "flux-system",
|
||||
Namespace: "flux-system",
|
||||
Branch: "main",
|
||||
Secret: "flux-system",
|
||||
ManifestFile: "gotk-sync.yaml",
|
||||
TargetPath: "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
|
||||
"github.com/fluxcd/flux2/pkg/manifestgen"
|
||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||
)
|
||||
|
||||
func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
@@ -67,7 +67,6 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
||||
SecretRef: &meta.LocalObjectReference{
|
||||
Name: options.Secret,
|
||||
},
|
||||
GitImplementation: options.GitImplementation,
|
||||
RecurseSubmodules: options.RecurseSubmodules,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !e2e
|
||||
// +build !e2e
|
||||
|
||||
/*
|
||||
@@ -23,8 +24,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||
)
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
|
||||
38
pkg/manifestgen/tmpdir.go
Normal file
38
pkg/manifestgen/tmpdir.go
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package manifestgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// MkdirTempAbs creates a tmp dir and returns the absolute path to the dir.
|
||||
// This is required since certain OSes like MacOS create temporary files in
|
||||
// e.g. `/private/var`, to which `/var` is a symlink.
|
||||
func MkdirTempAbs(dir, pattern string) (string, error) {
|
||||
tmpDir, err := os.MkdirTemp(dir, pattern)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmpDir, err = filepath.EvalSymlinks(tmpDir)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error evaluating symlink: %w", err)
|
||||
}
|
||||
return tmpDir, nil
|
||||
}
|
||||
Reference in New Issue
Block a user