-
Notifications
You must be signed in to change notification settings - Fork 230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support OpenSSH private key format for Git SSH authentication #3103
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ import ( | |
giturls "github.com/rancher/fleet/pkg/git-urls" | ||
"github.com/sirupsen/logrus" | ||
"golang.org/x/crypto/ssh" | ||
"golang.org/x/crypto/ssh/agent" | ||
) | ||
|
||
const defaultBranch = "master" | ||
|
@@ -130,7 +131,11 @@ func createAuthFromOpts(opts *GitCloner) (transport.AuthMethod, error) { | |
} | ||
auth, err := gossh.NewPublicKeys(gitURL.User.Username(), privateKey, "") | ||
if err != nil { | ||
return nil, err | ||
// Try to parse as OpenSSH private key | ||
auth, err = gossh.NewPublicKeys(gitURL.User.Username(), privateKey, "") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why retry the exact same operation as the one that has just failed? |
||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
if opts.KnownHostsFile != "" { | ||
knownHosts, err := readFile(opts.KnownHostsFile) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ type GitCloner struct { | |
SSHPrivateKeyFile string | ||
InsecureSkipTLS bool | ||
KnownHostsFile string | ||
OAuthToken string | ||
} | ||
|
||
var opts *GitCloner | ||
|
@@ -27,7 +28,10 @@ func NewCmd(gitCloner CloneGit) *cobra.Command { | |
cmd := &cobra.Command{ | ||
Use: "gitcloner [REPO] [PATH]", | ||
Short: "Clones a git repository", | ||
Args: cobra.ExactArgs(2), | ||
Long: `The gitcloner command clones a git repository to a specified path. | ||
It supports various authentication methods, including basic auth, SSH private keys, and OAuth tokens. | ||
You can also specify a default branch other than "master" if none is provided.`, | ||
Args: cobra.ExactArgs(2), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
opts.Repo = args[0] | ||
opts.Path = args[1] | ||
|
@@ -36,14 +40,15 @@ func NewCmd(gitCloner CloneGit) *cobra.Command { | |
}, | ||
} | ||
opts = &GitCloner{} | ||
cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "git branch") | ||
cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "git branch (default is 'master')") | ||
cmd.Flags().StringVar(&opts.Revision, "revision", "", "git revision") | ||
cmd.Flags().StringVar(&opts.CABundleFile, "ca-bundle-file", "", "CA bundle file") | ||
cmd.Flags().StringVarP(&opts.Username, "username", "u", "", "user name for basic auth") | ||
cmd.Flags().StringVar(&opts.PasswordFile, "password-file", "", "password file for basic auth") | ||
cmd.Flags().StringVar(&opts.SSHPrivateKeyFile, "ssh-private-key-file", "", "ssh private key file path") | ||
cmd.Flags().BoolVar(&opts.InsecureSkipTLS, "insecure-skip-tls", false, "do not verify tls certificates") | ||
cmd.Flags().StringVar(&opts.KnownHostsFile, "known-hosts-file", "", "known hosts file") | ||
cmd.Flags().StringVar(&opts.OAuthToken, "oauth-token", "", "OAuth token for authentication") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this option used? |
||
|
||
return cmd | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,7 +39,11 @@ func GetAuthFromSecret(url string, creds *corev1.Secret) (transport.AuthMethod, | |
} | ||
auth, err := gossh.NewPublicKeys(gitURL.User.Username(), creds.Data[corev1.SSHAuthPrivateKey], "") | ||
if err != nil { | ||
return nil, err | ||
// Try to parse as OpenSSH private key | ||
auth, err = gossh.NewPublicKeys(gitURL.User.Username(), creds.Data[corev1.SSHAuthPrivateKey], "") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same remark as in |
||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
if creds.Data["known_hosts"] != nil { | ||
auth.HostKeyCallback, err = newCreateKnownHosts(creds.Data["known_hosts"]) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -250,6 +250,36 @@ YcwLYudAztZeA/A4aM5Y0MA6PlNIeoHohuMkSZNOBcvkNEWdzGBpKb34yLfMarNm | |
Expect(err.Error()).To(ContainSubstring("knownhosts: missing host pattern")) | ||
}) | ||
}) | ||
|
||
Context("SSH auth with valid OpenSSH private key and no known_hosts", func() { | ||
var privateKey = []byte(`-----BEGIN OPENSSH PRIVATE KEY----- | ||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS | ||
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTi1hnnqv3tZiv8x+O1HkHjLXYfjRM+ | ||
o+8aeXACDXFdqT1oALLsoeXbpjL9UZAta69KZlnpAqDJ0dnOPj5ZUaq0AAAAsLX33E2199 | ||
xNAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOLWGeeq/e1mK/zH | ||
47UeQeMtdh+NEz6j7xp5cAINcV2pPWgAsuyh5dumMv1RkC1rr0pmWekCoMnR2c4+PllRqr | ||
QAAAAhAOZAKlM42hgAOsRnvRk/wp1mYy+raMO2p05D9BaLcD7oAAAAEXJvb3RAOTQ0YmM1 | ||
OTIyYTI4AQIDBAUG | ||
-----END OPENSSH PRIVATE KEY-----`) | ||
BeforeEach(func() { | ||
secret = &corev1.Secret{ | ||
Type: corev1.SecretTypeSSHAuth, | ||
Data: map[string][]byte{ | ||
corev1.SSHAuthPrivateKey: privateKey, | ||
}, | ||
} | ||
}) | ||
It("returns no error and the ssh auth", func() { | ||
auth, err := git.GetAuthFromSecret("[email protected]:rancher/fleet.git", secret) | ||
Expect(err).ToNot(HaveOccurred()) | ||
expectedSigner, err := ssh.ParsePrivateKey(privateKey) | ||
Expect(err).ToNot(HaveOccurred()) | ||
pk, ok := auth.(*gossh.PublicKeys) | ||
Expect(ok).To(BeTrue()) | ||
Expect(pk.User).To(Equal("git")) | ||
Expect(pk.Signer).To(Equal(expectedSigner)) | ||
}) | ||
}) | ||
}) | ||
|
||
var _ = Describe("git's GetHTTPClientFromSecret tests", func() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why we'd need this new import 🤔