Skip to content

Commit eb7d746

Browse files
authored
authn: also read mount secrets (#1560)
Fixes: #1558 Signed-off-by: Luiz Carvalho <lucarval@redhat.com>
1 parent 62f183e commit eb7d746

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

pkg/authn/kubernetes/keychain.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ type Options struct {
5858
// ImagePullSecrets holds the names of the Kubernetes secrets (scoped to
5959
// Namespace) containing credential data to use for the image pull.
6060
ImagePullSecrets []string
61+
62+
// UseMountSecrets determines whether or not mount secrets in the ServiceAccount
63+
// should be considered. Mount secrets are those listed under the `.secrets`
64+
// attribute of the ServiceAccount resource. Ignored if ServiceAccountName is set
65+
// to NoServiceAccount.
66+
UseMountSecrets bool
6167
}
6268

6369
// New returns a new authn.Keychain suitable for resolving image references as
@@ -111,6 +117,19 @@ func New(ctx context.Context, client kubernetes.Interface, opt Options) (authn.K
111117
}
112118
pullSecrets = append(pullSecrets, *ps)
113119
}
120+
121+
if opt.UseMountSecrets {
122+
for _, obj := range sa.Secrets {
123+
s, err := client.CoreV1().Secrets(opt.Namespace).Get(ctx, obj.Name, metav1.GetOptions{})
124+
if k8serrors.IsNotFound(err) {
125+
logs.Warn.Printf("secret %s/%s not found; ignoring", opt.Namespace, obj.Name)
126+
continue
127+
} else if err != nil {
128+
return nil, err
129+
}
130+
pullSecrets = append(pullSecrets, *s)
131+
}
132+
}
114133
}
115134
}
116135

pkg/authn/kubernetes/keychain_test.go

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/google/go-containerregistry/pkg/name"
2929
corev1 "k8s.io/api/core/v1"
3030
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31+
"k8s.io/apimachinery/pkg/runtime"
3132
fakeclient "k8s.io/client-go/kubernetes/fake"
3233
)
3334

@@ -131,7 +132,7 @@ func TestServiceAccountNotFound(t *testing.T) {
131132
testResolve(t, kc, registry(t, "fake.registry.io"), authn.Anonymous)
132133
}
133134

134-
func TestAttachedServiceAccount(t *testing.T) {
135+
func TestImagePullSecretAttachedServiceAccount(t *testing.T) {
135136
username, password := "foo", "bar"
136137
client := fakeclient.NewSimpleClientset(&corev1.ServiceAccount{
137138
ObjectMeta: metav1.ObjectMeta{
@@ -160,6 +161,73 @@ func TestAttachedServiceAccount(t *testing.T) {
160161
&authn.Basic{Username: username, Password: password})
161162
}
162163

164+
func TestSecretAttachedServiceAccount(t *testing.T) {
165+
username, password := "foo", "bar"
166+
167+
cases := []struct {
168+
name string
169+
createSecret bool
170+
useMountSecrets bool
171+
expected authn.Authenticator
172+
}{
173+
{
174+
name: "resolved successfully",
175+
createSecret: true,
176+
useMountSecrets: true,
177+
expected: &authn.Basic{Username: username, Password: password},
178+
},
179+
{
180+
name: "missing secret skipped",
181+
createSecret: false,
182+
useMountSecrets: true,
183+
expected: &authn.Basic{},
184+
},
185+
{
186+
name: "skip option",
187+
createSecret: true,
188+
useMountSecrets: false,
189+
expected: &authn.Basic{},
190+
},
191+
}
192+
193+
for _, c := range cases {
194+
t.Run(c.name, func(t *testing.T) {
195+
196+
objs := []runtime.Object{
197+
&corev1.ServiceAccount{
198+
ObjectMeta: metav1.ObjectMeta{
199+
Name: "svcacct",
200+
Namespace: "ns",
201+
},
202+
Secrets: []corev1.ObjectReference{{
203+
Name: "secret",
204+
}},
205+
},
206+
}
207+
if c.createSecret {
208+
objs = append(objs, dockerCfgSecretType.Create(
209+
t, "ns", "secret", "fake.registry.io", authn.AuthConfig{
210+
Username: username,
211+
Password: password,
212+
}))
213+
}
214+
client := fakeclient.NewSimpleClientset(objs...)
215+
216+
kc, err := New(context.Background(), client, Options{
217+
Namespace: "ns",
218+
ServiceAccountName: "svcacct",
219+
UseMountSecrets: c.useMountSecrets,
220+
})
221+
if err != nil {
222+
t.Fatalf("New() = %v", err)
223+
}
224+
225+
testResolve(t, kc, registry(t, "fake.registry.io"), c.expected)
226+
})
227+
}
228+
229+
}
230+
163231
// Prioritze picking the first secret
164232
func TestSecretPriority(t *testing.T) {
165233
secrets := []corev1.Secret{

0 commit comments

Comments
 (0)