@ -26,12 +26,12 @@ import (
"path"
"time"
"github.com/fluxcd/pkg/git/github"
cryptssh "golang.org/x/crypto/ssh"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
"github.com/fluxcd/pkg/runtime/secrets"
"github.com/fluxcd/pkg/ssh"
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
@ -60,7 +60,7 @@ type DockerConfigEntry struct {
Auth string ` json:"auth,omitempty" `
}
func Generate ( options Options ) ( * manifestgen . Manifest , error ) {
func Generate Git ( options Options ) ( * manifestgen . Manifest , error ) {
var err error
var keypair * ssh . KeyPair
@ -82,24 +82,173 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
}
}
var dockerCfgJson [ ] byte
if options . Registry != "" {
dockerCfgJson , err = GenerateDockerConfigJson ( options . Registry , options . Username , options . Password )
secret := buildGitSecret ( keypair , hostKey , options )
return secretToManifest ( & secret , options )
}
func GenerateTLS ( options Options ) ( * manifestgen . Manifest , error ) {
var opts [ ] secrets . TLSSecretOption
if len ( options . TLSCrt ) > 0 || len ( options . TLSKey ) > 0 {
opts = append ( opts , secrets . WithCertKeyPair ( options . TLSCrt , options . TLSKey ) )
}
if len ( options . CACrt ) > 0 {
opts = append ( opts , secrets . WithCAData ( options . CACrt ) )
}
secret , err := secrets . MakeTLSSecret ( options . Name , options . Namespace , opts ... )
if err != nil {
return nil , err
}
secret . Labels = options . Labels
return secretToManifest ( secret , options )
}
func GenerateOCI ( options Options ) ( * manifestgen . Manifest , error ) {
secret , err := secrets . MakeRegistrySecret (
options . Name ,
options . Namespace ,
options . Registry ,
options . Username ,
options . Password ,
)
if err != nil {
return nil , err
}
secret . Labels = options . Labels
return secretToManifest ( secret , options )
}
func GenerateHelm ( options Options ) ( * manifestgen . Manifest , error ) {
hasBasicAuth := options . Username != "" || options . Password != ""
hasClientCert := len ( options . TLSCrt ) > 0 || len ( options . TLSKey ) > 0
hasCACert := len ( options . CACrt ) > 0
var secret * corev1 . Secret
var err error
switch {
case hasClientCert :
// Priority 1: Client certificate (mTLS) - highest priority like CertSecretRef
var opts [ ] secrets . TLSSecretOption
opts = append ( opts , secrets . WithCertKeyPair ( options . TLSCrt , options . TLSKey ) )
if hasCACert {
opts = append ( opts , secrets . WithCAData ( options . CACrt ) )
}
secret , err = secrets . MakeTLSSecret ( options . Name , options . Namespace , opts ... )
if err != nil {
return nil , err
}
case hasBasicAuth :
// Priority 2: Basic authentication (can include CA certificate)
secret , err = secrets . MakeBasicAuthSecret (
options . Name ,
options . Namespace ,
options . Username ,
options . Password ,
)
if err != nil {
return nil , err
}
// Add CA certificate to BasicAuth secret for HTTPS repositories with custom CA
// (e.g., self-signed certificates or internal certificate authorities)
if hasCACert {
if secret . StringData == nil {
secret . StringData = make ( map [ string ] string )
}
secret . StringData [ CACrtSecretKey ] = string ( options . CACrt )
}
case hasCACert :
// Priority 3: CA certificate only
var opts [ ] secrets . TLSSecretOption
opts = append ( opts , secrets . WithCAData ( options . CACrt ) )
secret , err = secrets . MakeTLSSecret ( options . Name , options . Namespace , opts ... )
if err != nil {
return nil , fmt . Errorf ( "failed to generate json for docker config: %w" , err )
return nil , err
}
default :
// No authentication credentials provided - create empty secret for backward compatibility
secret = & corev1 . Secret {
TypeMeta : metav1 . TypeMeta {
APIVersion : "v1" ,
Kind : "Secret" ,
} ,
ObjectMeta : metav1 . ObjectMeta {
Name : options . Name ,
Namespace : options . Namespace ,
} ,
StringData : map [ string ] string { } ,
}
}
secret := buildSecret ( keypair , hostKey , dockerCfgJson , options )
b , err := yaml . Marshal ( secret )
secret . Labels = options . Labels
return secretToManifest ( secret , options )
}
func GenerateProxy ( options Options ) ( * manifestgen . Manifest , error ) {
secret , err := secrets . MakeProxySecret (
options . Name ,
options . Namespace ,
options . Address ,
options . Username ,
options . Password ,
)
if err != nil {
return nil , err
}
return & manifestgen . Manifest {
Path : path . Join ( options . TargetPath , options . Namespace , options . ManifestFile ) ,
Content : fmt . Sprintf ( "---\n%s" , resourceToString ( b ) ) ,
} , nil
secret . Labels = options . Labels
return secretToManifest ( secret , options )
}
func GenerateNotation ( options Options ) ( * manifestgen . Manifest , error ) {
secret := & corev1 . Secret {
TypeMeta : metav1 . TypeMeta {
APIVersion : "v1" ,
Kind : "Secret" ,
} ,
ObjectMeta : metav1 . ObjectMeta {
Name : options . Name ,
Namespace : options . Namespace ,
Labels : options . Labels ,
} ,
StringData : map [ string ] string { } ,
}
for _ , crt := range options . VerificationCrts {
secret . StringData [ crt . Name ] = string ( crt . CACrt )
}
if len ( options . TrustPolicy ) > 0 {
secret . StringData [ TrustPolicyKey ] = string ( options . TrustPolicy )
}
return secretToManifest ( secret , options )
}
func GenerateGitHubApp ( options Options ) ( * manifestgen . Manifest , error ) {
secret , err := secrets . MakeGitHubAppSecret (
options . Name ,
options . Namespace ,
options . GitHubAppID ,
options . GitHubAppInstallationID ,
options . GitHubAppPrivateKey ,
options . GitHubAppBaseURL ,
)
if err != nil {
return nil , err
}
secret . Labels = options . Labels
return secretToManifest ( secret , options )
}
func LoadKeyPairFromPath ( path , password string ) ( * ssh . KeyPair , error ) {
@ -131,7 +280,7 @@ func LoadKeyPair(privateKey []byte, password string) (*ssh.KeyPair, error) {
} , nil
}
func build Secret( keypair * ssh . KeyPair , hostKey , dockerCfg [ ] byte , options Options ) ( secret corev1 . Secret ) {
func build Git Secret( keypair * ssh . KeyPair , hostKey [ ] byte , options Options ) ( secret corev1 . Secret ) {
secret . TypeMeta = metav1 . TypeMeta {
APIVersion : "v1" ,
Kind : "Secret" ,
@ -143,16 +292,6 @@ func buildSecret(keypair *ssh.KeyPair, hostKey, dockerCfg []byte, options Option
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 . Address != "" {
secret . StringData [ AddressSecretKey ] = options . Address
}
if options . Username != "" && options . Password != "" {
secret . StringData [ UsernameSecretKey ] = options . Username
secret . StringData [ PasswordSecretKey ] = options . Password
@ -165,12 +304,7 @@ func buildSecret(keypair *ssh.KeyPair, hostKey, dockerCfg []byte, options Option
secret . StringData [ CACrtSecretKey ] = string ( options . CACrt )
}
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 )
}
// SSH keypair (identity + identity.pub + known_hosts)
if keypair != nil && len ( hostKey ) != 0 {
secret . StringData [ PrivateKeySecretKey ] = string ( keypair . PrivateKey )
secret . StringData [ PublicKeySecretKey ] = string ( keypair . PublicKey )
@ -181,33 +315,18 @@ func buildSecret(keypair *ssh.KeyPair, hostKey, dockerCfg []byte, options Option
}
}
if len ( options . VerificationCrts ) != 0 {
for _ , crts := range options . VerificationCrts {
secret . StringData [ crts . Name ] = string ( crts . CACrt )
}
}
if len ( options . TrustPolicy ) != 0 {
secret . StringData [ TrustPolicyKey ] = string ( options . TrustPolicy )
}
if options . GitHubAppID != "" {
secret . StringData [ github . KeyAppID ] = options . GitHubAppID
}
if options . GitHubAppInstallationID != "" {
secret . StringData [ github . KeyAppInstallationID ] = options . GitHubAppInstallationID
}
if options . GitHubAppPrivateKey != "" {
secret . StringData [ github . KeyAppPrivateKey ] = options . GitHubAppPrivateKey
}
return secret
}
if options . GitHubAppBaseURL != "" {
secret . StringData [ github . KeyAppBaseURL ] = options . GitHubAppBaseURL
func secretToManifest ( secret * corev1 . Secret , options Options ) ( * manifestgen . Manifest , error ) {
b , err := yaml . Marshal ( secret )
if err != nil {
return nil , err
}
return
return & manifestgen . Manifest {
Path : path . Join ( options . TargetPath , options . Namespace , options . ManifestFile ) ,
Content : fmt . Sprintf ( "---\n%s" , resourceToString ( b ) ) ,
} , nil
}
func generateKeyPair ( options Options ) ( * ssh . KeyPair , error ) {