Skip to content

Commit baaa950

Browse files
authored
Merge pull request #631 from abhilashjoseph/master
Use registry authentication for azure sp credentials, when authType is azureCloudConfig
2 parents ffbc2f5 + 5a546e0 commit baaa950

File tree

7 files changed

+145
-22
lines changed

7 files changed

+145
-22
lines changed

cmd/azure-keyvault-controller/main.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ func main() {
102102

103103
if logFormat == "json" {
104104
loggerFactory := jsonlogs.Factory{}
105-
logger, _ := loggerFactory.Create(logConfig.LoggingConfiguration{}, logConfig.LoggingOptions{})
105+
logger, _ := loggerFactory.Create(*logConfig.NewLoggingConfiguration(), logConfig.LoggingOptions{
106+
ErrorStream: os.Stderr,
107+
InfoStream: os.Stdout,
108+
})
106109
klog.SetLogger(logger)
107110
}
108111
klog.InfoS("log settings", "format", logFormat, "level", flag.Lookup("v").Value)

cmd/azure-keyvault-env/environment.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
const (
12-
envLookupRegex = `^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)@azurekeyvault(\?([a-zA-Z_][a-zA-Z0-9_\.]*)?)?$`
12+
envLookupRegex = `^([a-zA-Z0-9]([a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)@azurekeyvault(\?([a-zA-Z_][a-zA-Z0-9_\.]*)?)?$`
1313
)
1414

1515
type EnvSecret struct {

cmd/azure-keyvault-env/main.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,10 @@ func main() {
157157

158158
if logFormat == "json" {
159159
loggerFactory := jsonlogs.Factory{}
160-
logger, _ := loggerFactory.Create(logConfig.LoggingConfiguration{}, logConfig.LoggingOptions{})
160+
logger, _ := loggerFactory.Create(*logConfig.NewLoggingConfiguration(), logConfig.LoggingOptions{
161+
ErrorStream: os.Stderr,
162+
InfoStream: os.Stdout,
163+
})
161164
klog.SetLogger(logger)
162165
}
163166

cmd/azure-keyvault-secrets-webhook/main.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,11 @@ func main() {
231231

232232
if params.logFormat == "json" {
233233
loggerFactory := jsonlogs.Factory{}
234-
logger, _ := loggerFactory.Create(logConfig.LoggingConfiguration{}, logConfig.LoggingOptions{})
234+
logger, _ := loggerFactory.Create(*logConfig.NewLoggingConfiguration(), logConfig.LoggingOptions{
235+
ErrorStream: os.Stderr,
236+
InfoStream: os.Stdout,
237+
})
238+
235239
klog.SetLogger(logger)
236240
}
237241

@@ -319,7 +323,7 @@ func main() {
319323
wg := new(sync.WaitGroup)
320324
wg.Add(2)
321325

322-
config.registry = registry.NewRegistry(config.cloudConfig)
326+
config.registry = registry.NewRegistry(config.authType, config.credentialProvider)
323327

324328
createHTTPEndpoint(wg, config.httpPort, config.useAuthService, config.authService)
325329
createMTLSEndpoint(wg, config.mtlsPort, config.useAuthService, config.authService)

pkg/azure/credentialprovider/acr.go

+5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ func (c CloudConfigCredentialProvider) GetAcrCredentials(image string) (k8sCrede
6969
Password: "",
7070
}
7171

72+
if !c.IsAcrRegistry(image) {
73+
klog.V(4).Info("image not from acr, returning empty credentials")
74+
return cred, nil
75+
}
76+
7277
if c.config.UseManagedIdentityExtension {
7378
klog.V(4).Info("using managed identity for acr credentials")
7479
loginServer := parseACRLoginServerFromImage(image, c.environment)

pkg/docker/registry/registry.go

+79-17
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323
"fmt"
2424
"net/http"
2525

26+
"github.com/SparebankenVest/azure-key-vault-to-kubernetes/pkg/azure/credentialprovider"
27+
"github.com/google/go-containerregistry/pkg/authn"
2628
"github.com/google/go-containerregistry/pkg/authn/k8schain"
2729
"github.com/google/go-containerregistry/pkg/name"
2830
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -50,13 +52,17 @@ type ImageRegistryOptions struct {
5052

5153
// Registry impl
5254
type Registry struct {
53-
imageCache *cache.Cache
55+
authType string
56+
imageCache *cache.Cache
57+
credentialProvider credentialprovider.CredentialProvider
5458
}
5559

5660
// NewRegistry creates and initializes registry
57-
func NewRegistry(cloudConfigPath string) ImageRegistry {
61+
func NewRegistry(authType string, credentialProvider credentialprovider.CredentialProvider) ImageRegistry {
5862
return &Registry{
59-
imageCache: cache.New(cache.NoExpiration, cache.NoExpiration),
63+
authType: authType,
64+
imageCache: cache.New(cache.NoExpiration, cache.NoExpiration),
65+
credentialProvider: credentialProvider,
6066
}
6167
}
6268

@@ -100,31 +106,83 @@ func (r *Registry) GetImageConfig(
100106
containerInfo.ImagePullSecrets = append(containerInfo.ImagePullSecrets, imagePullSecret.Name)
101107
}
102108

103-
imageConfig, err := getImageConfig(ctx, client, containerInfo, opt)
109+
remoteOptions, err := getContainerRegistryRemoteOptions(ctx, client, containerInfo, r.authType, opt, r.credentialProvider)
110+
if err != nil {
111+
return nil, fmt.Errorf("failed to get remote options: %w", err)
112+
}
113+
114+
imageConfig, err := getImageConfig(containerInfo, remoteOptions)
104115
if imageConfig != nil && allowToCache {
105116
r.imageCache.Set(container.Image, imageConfig, cache.DefaultExpiration)
106117
}
107118

108119
return imageConfig, err
109120
}
110121

111-
// getImageConfig download image blob from registry
112-
func getImageConfig(ctx context.Context, client kubernetes.Interface, container containerInfo, opt ImageRegistryOptions) (*v1.Config, error) {
113-
authChain, err := k8schain.New(
114-
ctx,
115-
client,
116-
k8schain.Options{
117-
Namespace: container.Namespace,
118-
ServiceAccountName: container.ServiceAccountName,
119-
ImagePullSecrets: container.ImagePullSecrets,
120-
},
121-
)
122+
// getContainerRegistryRemoteOptions get container registry remote option
123+
func getContainerRegistryRemoteOptions(ctx context.Context, client kubernetes.Interface, container containerInfo, authType string, opt ImageRegistryOptions, r credentialprovider.CredentialProvider) ([]remote.Option, error) {
124+
ref, err := name.ParseReference(container.Image)
122125
if err != nil {
123-
return nil, err
126+
return nil, fmt.Errorf("failed to parse image reference: %w", err)
127+
}
128+
registry := ref.Context().Registry.Name()
129+
130+
klog.InfoS("using registry", "imageRegistry", registry)
131+
132+
authChain := new(authn.Keychain)
133+
switch authType {
134+
case "azureCloudConfig":
135+
klog.InfoS("using cloudConfig for registry authentication", "config.authType", authType)
136+
dockerConfigEntry, err := r.GetAcrCredentials(container.Image)
137+
if err != nil {
138+
return nil, fmt.Errorf("cannot fetch acr credentials: %w", err)
139+
}
140+
141+
if dockerConfigEntry.Username != "" {
142+
143+
sec := []corev1.Secret{ //{
144+
*dockerCfgSecretType.Create(container.Namespace, "secret", registry, authn.AuthConfig{
145+
Username: dockerConfigEntry.Username, Password: dockerConfigEntry.Password,
146+
}),
147+
}
148+
*authChain, err = k8schain.NewFromPullSecrets(
149+
ctx,
150+
sec,
151+
)
152+
if err != nil {
153+
return nil, err
154+
}
155+
} else {
156+
*authChain, err = k8schain.New(
157+
ctx,
158+
client,
159+
k8schain.Options{
160+
Namespace: container.Namespace,
161+
ServiceAccountName: container.ServiceAccountName},
162+
)
163+
if err != nil {
164+
return nil, err
165+
}
166+
}
167+
168+
default:
169+
klog.InfoS("using imagePullSecrets for registry authentication", "config.authType", authType)
170+
*authChain, err = k8schain.New(
171+
ctx,
172+
client,
173+
k8schain.Options{
174+
Namespace: container.Namespace,
175+
ServiceAccountName: container.ServiceAccountName,
176+
ImagePullSecrets: container.ImagePullSecrets,
177+
},
178+
)
179+
if err != nil {
180+
return nil, err
181+
}
124182
}
125183

126184
options := []remote.Option{
127-
remote.WithAuthFromKeychain(authChain),
185+
remote.WithAuthFromKeychain(*authChain),
128186
}
129187

130188
if opt.SkipVerify {
@@ -133,7 +191,11 @@ func getImageConfig(ctx context.Context, client kubernetes.Interface, container
133191
}
134192
options = append(options, remote.WithTransport(tr))
135193
}
194+
return options, err
195+
}
136196

197+
// getImageConfig download image blob from registry
198+
func getImageConfig(container containerInfo, options []remote.Option) (*v1.Config, error) {
137199
ref, err := name.ParseReference(container.Image)
138200
if err != nil {
139201
return nil, fmt.Errorf("failed to parse image reference: %w", err)
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package registry
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"github.com/google/go-containerregistry/pkg/authn"
8+
corev1 "k8s.io/api/core/v1"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
)
11+
12+
type secretType struct {
13+
name corev1.SecretType
14+
key string
15+
marshal func(registry string, auth authn.AuthConfig) []byte
16+
}
17+
18+
func (s *secretType) Create(namespace, name string, registry string, auth authn.AuthConfig) *corev1.Secret {
19+
return &corev1.Secret{
20+
ObjectMeta: metav1.ObjectMeta{
21+
Name: name,
22+
Namespace: namespace,
23+
},
24+
Type: s.name,
25+
Data: map[string][]byte{
26+
s.key: s.marshal(registry, auth),
27+
},
28+
}
29+
}
30+
31+
var dockerCfgSecretType = secretType{
32+
name: corev1.SecretTypeDockercfg,
33+
key: corev1.DockerConfigKey,
34+
marshal: func(target string, auth authn.AuthConfig) []byte {
35+
return toJSON(map[string]authn.AuthConfig{target: auth})
36+
},
37+
}
38+
39+
func toJSON(obj any) []byte {
40+
bites, err := json.Marshal(obj)
41+
42+
if err != nil {
43+
fmt.Errorf("unable to json marshal: %w", err)
44+
}
45+
return bites
46+
}

0 commit comments

Comments
 (0)