Implement Git SSH authentication
This commit is contained in:
parent
bbc25c3de0
commit
06af12739d
|
@ -21,6 +21,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ import (
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -153,22 +155,30 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auth, err := r.auth(repository)
|
// create tmp dir for SSH known_hosts
|
||||||
|
tmpSSH, err := ioutil.TempDir("", repository.Name)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("tmp dir error %w", err)
|
||||||
|
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpSSH)
|
||||||
|
|
||||||
|
auth, err := r.auth(repository, tmpSSH)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("auth error %w", err)
|
err = fmt.Errorf("auth error %w", err)
|
||||||
return NotReadyCondition(sourcev1.AuthenticationFailedReason, err.Error()), "", err
|
return NotReadyCondition(sourcev1.AuthenticationFailedReason, err.Error()), "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create tmp dir
|
// create tmp dir for the Git clone
|
||||||
dir, err := ioutil.TempDir("", repository.Name)
|
tmpGit, err := ioutil.TempDir("", repository.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("tmp dir error %w", err)
|
err = fmt.Errorf("tmp dir error %w", err)
|
||||||
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
|
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(tmpGit)
|
||||||
|
|
||||||
// clone to tmp
|
// clone to tmp
|
||||||
repo, err := git.PlainClone(dir, false, &git.CloneOptions{
|
repo, err := git.PlainClone(tmpGit, false, &git.CloneOptions{
|
||||||
URL: repository.Spec.URL,
|
URL: repository.Spec.URL,
|
||||||
Auth: auth,
|
Auth: auth,
|
||||||
RemoteName: "origin",
|
RemoteName: "origin",
|
||||||
|
@ -256,6 +266,7 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read commit hash
|
// read commit hash
|
||||||
ref, err := repo.Head()
|
ref, err := repo.Head()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -282,7 +293,7 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
// archive artifact
|
// archive artifact
|
||||||
err = r.Storage.Archive(artifact, dir, "")
|
err = r.Storage.Archive(artifact, tmpGit, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("storage error %w", err)
|
err = fmt.Errorf("storage error %w", err)
|
||||||
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
|
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
|
||||||
|
@ -329,7 +340,7 @@ func (r *GitRepositoryReconciler) gc(repository sourcev1.GitRepository) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *GitRepositoryReconciler) auth(repository sourcev1.GitRepository) (transport.AuthMethod, error) {
|
func (r *GitRepositoryReconciler) auth(repository sourcev1.GitRepository, tmp string) (transport.AuthMethod, error) {
|
||||||
if repository.Spec.SecretRef == nil {
|
if repository.Spec.SecretRef == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -347,21 +358,53 @@ func (r *GitRepositoryReconciler) auth(repository sourcev1.GitRepository) (trans
|
||||||
|
|
||||||
credentials := secret.Data
|
credentials := secret.Data
|
||||||
|
|
||||||
// extract HTTP credentials
|
// HTTP auth
|
||||||
if strings.HasPrefix(repository.Spec.URL, "http") {
|
if strings.HasPrefix(repository.Spec.URL, "http") {
|
||||||
auth := &http.BasicAuth{}
|
auth := &http.BasicAuth{}
|
||||||
if username, ok := credentials["username"]; ok {
|
if username, ok := credentials["username"]; ok {
|
||||||
auth.Username = string(username)
|
auth.Username = string(username)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("%s secret does not contain a username", repository.Spec.SecretRef.Name)
|
return nil, fmt.Errorf("%s secret does not contain username", repository.Spec.SecretRef.Name)
|
||||||
}
|
}
|
||||||
if password, ok := credentials["password"]; ok {
|
if password, ok := credentials["password"]; ok {
|
||||||
auth.Password = string(password)
|
auth.Password = string(password)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("%s secret does not contain a password", repository.Spec.SecretRef.Name)
|
return nil, fmt.Errorf("%s secret does not contain password", repository.Spec.SecretRef.Name)
|
||||||
}
|
}
|
||||||
return auth, nil
|
return auth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SSH auth
|
||||||
|
if strings.HasPrefix(repository.Spec.URL, "ssh") {
|
||||||
|
var privateKey []byte
|
||||||
|
if identity, ok := credentials["identity"]; ok {
|
||||||
|
privateKey = identity
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("%s secret does not contain identity", repository.Spec.SecretRef.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pk, err := ssh.NewPublicKeys("git", privateKey, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
known_hosts := filepath.Join(tmp, "known_hosts")
|
||||||
|
if kh, ok := credentials["known_hosts"]; ok {
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(tmp, "known_hosts"), kh, 0644); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("%s secret does not contain known_hosts", repository.Spec.SecretRef.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback, err := ssh.NewKnownHostsCallback(known_hosts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pk.HostKeyCallback = callback
|
||||||
|
|
||||||
|
return pk, nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue