Implement Git HTTP authentication
This commit is contained in:
parent
e2d28296e1
commit
bbc25c3de0
|
@ -43,4 +43,8 @@ const (
|
||||||
|
|
||||||
// URLInvalidReason represents the fact that a given source has an invalid URL.
|
// URLInvalidReason represents the fact that a given source has an invalid URL.
|
||||||
URLInvalidReason string = "URLInvalid"
|
URLInvalidReason string = "URLInvalid"
|
||||||
|
|
||||||
|
// AuthenticationFailedReason represents the fact that a given secret doesn't
|
||||||
|
// have the required fields or the provided credentials don't match.
|
||||||
|
AuthenticationFailedReason string = "AuthenticationFailed"
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,6 +28,12 @@ type GitRepositorySpec struct {
|
||||||
// +required
|
// +required
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
|
|
||||||
|
// The secret name containing the Git credentials.
|
||||||
|
// For HTTPS repositories the secret must contain username and password fields.
|
||||||
|
// For SSH repositories the secret must contain identity, identity.pub and known_hosts fields.
|
||||||
|
// +optional
|
||||||
|
SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"`
|
||||||
|
|
||||||
// The interval at which to check for repository updates.
|
// The interval at which to check for repository updates.
|
||||||
// +required
|
// +required
|
||||||
Interval metav1.Duration `json:"interval"`
|
Interval metav1.Duration `json:"interval"`
|
||||||
|
|
|
@ -21,6 +21,7 @@ limitations under the License.
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -101,6 +102,11 @@ func (in *GitRepositoryRef) DeepCopy() *GitRepositoryRef {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *GitRepositorySpec) DeepCopyInto(out *GitRepositorySpec) {
|
func (in *GitRepositorySpec) DeepCopyInto(out *GitRepositorySpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.SecretRef != nil {
|
||||||
|
in, out := &in.SecretRef, &out.SecretRef
|
||||||
|
*out = new(v1.LocalObjectReference)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
out.Interval = in.Interval
|
out.Interval = in.Interval
|
||||||
if in.Reference != nil {
|
if in.Reference != nil {
|
||||||
in, out := &in.Reference, &out.Reference
|
in, out := &in.Reference, &out.Reference
|
||||||
|
|
|
@ -71,6 +71,17 @@ spec:
|
||||||
description: The git tag to checkout, takes precedence over branch.
|
description: The git tag to checkout, takes precedence over branch.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
secretRef:
|
||||||
|
description: The secret name containing the Git credentials. For HTTPS
|
||||||
|
repositories the secret must contain username and password fields.
|
||||||
|
For SSH repositories the secret must contain identity, identity.pub
|
||||||
|
and known_hosts fields.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||||
|
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
url:
|
url:
|
||||||
description: The repository URL, can be a HTTP or SSH address.
|
description: The repository URL, can be a HTTP or SSH address.
|
||||||
pattern: ^(http|https|ssh)://
|
pattern: ^(http|https|ssh)://
|
||||||
|
|
|
@ -27,10 +27,13 @@ import (
|
||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"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/http"
|
||||||
"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"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||||
|
@ -150,6 +153,12 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auth, err := r.auth(repository)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("auth error %w", err)
|
||||||
|
return NotReadyCondition(sourcev1.AuthenticationFailedReason, err.Error()), "", err
|
||||||
|
}
|
||||||
|
|
||||||
// create tmp dir
|
// create tmp dir
|
||||||
dir, err := ioutil.TempDir("", repository.Name)
|
dir, err := ioutil.TempDir("", repository.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -161,7 +170,7 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
|
||||||
// clone to tmp
|
// clone to tmp
|
||||||
repo, err := git.PlainClone(dir, false, &git.CloneOptions{
|
repo, err := git.PlainClone(dir, false, &git.CloneOptions{
|
||||||
URL: repository.Spec.URL,
|
URL: repository.Spec.URL,
|
||||||
Auth: nil,
|
Auth: auth,
|
||||||
RemoteName: "origin",
|
RemoteName: "origin",
|
||||||
ReferenceName: refName,
|
ReferenceName: refName,
|
||||||
SingleBranch: true,
|
SingleBranch: true,
|
||||||
|
@ -319,3 +328,40 @@ func (r *GitRepositoryReconciler) gc(repository sourcev1.GitRepository) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *GitRepositoryReconciler) auth(repository sourcev1.GitRepository) (transport.AuthMethod, error) {
|
||||||
|
if repository.Spec.SecretRef == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
name := types.NamespacedName{
|
||||||
|
Namespace: repository.GetNamespace(),
|
||||||
|
Name: repository.Spec.SecretRef.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
var secret corev1.Secret
|
||||||
|
err := r.Client.Get(context.TODO(), name, &secret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
credentials := secret.Data
|
||||||
|
|
||||||
|
// extract HTTP credentials
|
||||||
|
if strings.HasPrefix(repository.Spec.URL, "http") {
|
||||||
|
auth := &http.BasicAuth{}
|
||||||
|
if username, ok := credentials["username"]; ok {
|
||||||
|
auth.Username = string(username)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("%s secret does not contain a username", repository.Spec.SecretRef.Name)
|
||||||
|
}
|
||||||
|
if password, ok := credentials["password"]; ok {
|
||||||
|
auth.Password = string(password)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("%s secret does not contain a password", repository.Spec.SecretRef.Name)
|
||||||
|
}
|
||||||
|
return auth, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue