Update Helm to v3.6.1

v3.6.1 is a a security update from Helm, ensuring that credentials are
always only passed to the defined repository host.

Based on Helm user reports, disabling this behavior may be required for
some Helm repository solutions like Artifactory, and may be done by
setting `PassCredentials` in the `HelmRepositorySpec`.

For more information, see:
https://github.com/helm/helm/security/advisories/GHSA-56hp-xqp3-w2jf

Signed-off-by: Hidde Beydals <hello@hidde.co>
This commit is contained in:
Hidde Beydals 2021-06-17 16:23:09 +02:00
parent 1a75415103
commit 1f27410b34
9 changed files with 82 additions and 17 deletions

View File

@ -45,6 +45,15 @@ type HelmRepositorySpec struct {
// +optional
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
// PassCredentials allows the credentials from the SecretRef to be passed on to
// a host that does not match the host as defined in URL.
// This may be required if the host of the advertised chart URLs in the index
// differ from the defined URL.
// Enabling this should be done with caution, as it can potentially result in
// credentials getting stolen in a MITM-attack.
// +optional
PassCredentials bool `json:"passCredentials,omitempty"`
// The interval at which to check the upstream for updates.
// +required
Interval metav1.Duration `json:"interval"`

View File

@ -50,6 +50,9 @@ spec:
interval:
description: The interval at which to check the upstream for updates.
type: string
passCredentials:
description: PassCredentials allows the credentials from the SecretRef to be passed on to a host that does not match the host as defined in URL. This may be required if the host of the advertised chart URLs in the index differ from the defined URL. Enabling this should be done with caution, as it can potentially result in credentials getting stolen in a MITM-attack.
type: boolean
secretRef:
description: The name of the secret containing authentication credentials for the Helm repository. For HTTP/S basic auth the secret must contain username and password fields. For TLS the secret must contain a certFile and keyFile, and/or caCert fields.
properties:

View File

@ -301,7 +301,11 @@ func (r *HelmChartReconciler) getSource(ctx context.Context, chart sourcev1.Helm
func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
repository sourcev1.HelmRepository, chart sourcev1.HelmChart, force bool) (sourcev1.HelmChart, error) {
// Configure ChartRepository getter options
var clientOpts []getter.Option
clientOpts := []getter.Option{
getter.WithURL(repository.Spec.URL),
getter.WithTimeout(repository.Spec.Timeout.Duration),
getter.WithPassCredentialsAll(repository.Spec.PassCredentials),
}
if secret, err := r.getHelmRepositorySecret(ctx, &repository); err != nil {
return sourcev1.HelmChartNotReady(chart, sourcev1.AuthenticationFailedReason, err.Error()), err
} else if secret != nil {
@ -311,10 +315,8 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
return sourcev1.HelmChartNotReady(chart, sourcev1.AuthenticationFailedReason, err.Error()), err
}
defer cleanup()
clientOpts = opts
clientOpts = append(clientOpts, opts...)
}
clientOpts = append(clientOpts, getter.WithTimeout(repository.Spec.Timeout.Duration))
// Initialize the chart repository and load the index file
chartRepo, err := helm.NewChartRepository(repository.Spec.URL, r.Getters, clientOpts)
@ -619,13 +621,18 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
if err != nil {
repository = &sourcev1.HelmRepository{
Spec: sourcev1.HelmRepositorySpec{
URL: dep.Repository,
URL: dep.Repository,
Timeout: &metav1.Duration{Duration: 60 * time.Second},
},
}
}
// Configure ChartRepository getter options
var clientOpts []getter.Option
clientOpts := []getter.Option{
getter.WithURL(repository.Spec.URL),
getter.WithTimeout(repository.Spec.Timeout.Duration),
getter.WithPassCredentialsAll(repository.Spec.PassCredentials),
}
if secret, err := r.getHelmRepositorySecret(ctx, repository); err != nil {
return sourcev1.HelmChartNotReady(chart, sourcev1.AuthenticationFailedReason, err.Error()), err
} else if secret != nil {
@ -635,8 +642,7 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
return sourcev1.HelmChartNotReady(chart, sourcev1.AuthenticationFailedReason, err.Error()), err
}
defer cleanup()
clientOpts = opts
clientOpts = append(clientOpts, opts...)
}
// Initialize the chart repository and load the index file

View File

@ -1015,9 +1015,9 @@ var _ = Describe("HelmChartReconciler", func() {
Name: secretKey.Name,
Namespace: secretKey.Namespace,
},
Data: map[string][]byte{
"username": []byte(username),
"password": []byte(password),
StringData: map[string]string{
"username": username,
"password": password,
},
}
Expect(k8sClient.Create(context.Background(), secret)).Should(Succeed())

View File

@ -171,7 +171,11 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, repository sourcev1.HelmRepository) (sourcev1.HelmRepository, error) {
var clientOpts []getter.Option
clientOpts := []getter.Option{
getter.WithURL(repository.Spec.URL),
getter.WithTimeout(repository.Spec.Timeout.Duration),
getter.WithPassCredentialsAll(repository.Spec.PassCredentials),
}
if repository.Spec.SecretRef != nil {
name := types.NamespacedName{
Namespace: repository.GetNamespace(),
@ -191,9 +195,8 @@ func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, repository sou
return sourcev1.HelmRepositoryNotReady(repository, sourcev1.AuthenticationFailedReason, err.Error()), err
}
defer cleanup()
clientOpts = opts
clientOpts = append(clientOpts, opts...)
}
clientOpts = append(clientOpts, getter.WithTimeout(repository.Spec.Timeout.Duration))
chartRepo, err := helm.NewChartRepository(repository.Spec.URL, r.Getters, clientOpts)
if err != nil {

View File

@ -703,6 +703,23 @@ caCert fields.</p>
</tr>
<tr>
<td>
<code>passCredentials</code><br>
<em>
bool
</em>
</td>
<td>
<em>(Optional)</em>
<p>PassCredentials allows the credentials from the SecretRef to be passed on to
a host that does not match the host as defined in URL.
This may be required if the host of the advertised chart URLs in the index
differ from the defined URL.
Enabling this should be done with caution, as it can potentially result in
credentials getting stolen in a MITM-attack.</p>
</td>
</tr>
<tr>
<td>
<code>interval</code><br>
<em>
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
@ -1777,6 +1794,23 @@ caCert fields.</p>
</tr>
<tr>
<td>
<code>passCredentials</code><br>
<em>
bool
</em>
</td>
<td>
<em>(Optional)</em>
<p>PassCredentials allows the credentials from the SecretRef to be passed on to
a host that does not match the host as defined in URL.
This may be required if the host of the advertised chart URLs in the index
differ from the defined URL.
Enabling this should be done with caution, as it can potentially result in
credentials getting stolen in a MITM-attack.</p>
</td>
</tr>
<tr>
<td>
<code>interval</code><br>
<em>
<a href="https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">

View File

@ -21,9 +21,18 @@ type HelmRepositorySpec struct {
// password fields.
// For TLS the secret must contain a certFile and keyFile, and/or
// caCert fields.
// +optional
// +optional
SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"`
// PassCredentials allows the credentials from the SecretRef to be passed on to
// a host that does not match the host as defined in URL.
// This may be required if the host of the advertised chart URLs in the index
// differ from the defined URL.
// Enabling this should be done with caution, as it can potentially result in
// credentials getting stolen in a MITM-attack.
// +optional
PassCredentials bool `json:"passCredentials,omitempty"`
// The interval at which to check the upstream for updates.
// +required
Interval metav1.Duration `json:"interval"`

2
go.mod
View File

@ -29,7 +29,7 @@ require (
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
gotest.tools v2.2.0+incompatible
helm.sh/helm/v3 v3.6.0
helm.sh/helm/v3 v3.6.1
k8s.io/api v0.21.1
k8s.io/apimachinery v0.21.1
k8s.io/client-go v0.21.1

3
go.sum
View File

@ -1247,8 +1247,9 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
helm.sh/helm/v3 v3.6.0 h1:/9IMxJ2lXJHbvTMHcW1AO71lXQHqDC+3bcpGp7yCsb8=
helm.sh/helm/v3 v3.6.0/go.mod h1:mIIus8EOqj+obtycw3sidsR4ORr2aFDmXMSI3k+oeVY=
helm.sh/helm/v3 v3.6.1 h1:TQ6q4pAatXr7qh2fbLcb0oNd0I3J7kv26oo5cExKTtc=
helm.sh/helm/v3 v3.6.1/go.mod h1:mIIus8EOqj+obtycw3sidsR4ORr2aFDmXMSI3k+oeVY=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=