File: keychain.go

package info (click to toggle)
golang-github-containerd-nydus-snapshotter 0.13.4-2.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,824 kB
  • sloc: sh: 470; makefile: 129
file content (136 lines) | stat: -rw-r--r-- 3,105 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * Copyright (c) 2020. Ant Group. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

package auth

import (
	"encoding/base64"
	"fmt"
	"strings"

	"github.com/pkg/errors"

	"github.com/containerd/containerd/reference/docker"
	"github.com/containerd/nydus-snapshotter/pkg/label"
	"github.com/google/go-containerregistry/pkg/authn"
)

const (
	sep = ":"
)

var (
	emptyPassKeyChain = PassKeyChain{}
)

// PassKeyChain is user/password based key chain
type PassKeyChain struct {
	Username string
	Password string
}

func FromBase64(str string) (PassKeyChain, error) {
	decoded, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return emptyPassKeyChain, err
	}
	pair := strings.Split(string(decoded), sep)
	if len(pair) != 2 {
		return emptyPassKeyChain, errors.New("invalid registry auth token")
	}
	return PassKeyChain{
		Username: pair[0],
		Password: pair[1],
	}, nil
}

func (kc PassKeyChain) ToBase64() string {
	if kc.Username == "" && kc.Password == "" {
		return ""
	}
	return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", kc.Username, kc.Password)))
}

// TokenBase check if PassKeyChain is token based, when username is empty and password is not empty
// then password is registry token
func (kc PassKeyChain) TokenBase() bool {
	return kc.Username == "" && kc.Password != ""
}

// FromLabels finds image pull username and secret from snapshot labels.
// Returned `nil` means no valid username and secret is passed, it should
// not override input nydusd configuration.
func FromLabels(labels map[string]string) *PassKeyChain {
	u, found := labels[label.NydusImagePullUsername]
	if !found || u == "" {
		return nil
	}

	p, found := labels[label.NydusImagePullSecret]
	if !found || p == "" {
		return nil
	}

	return &PassKeyChain{
		Username: u,
		Password: p,
	}
}

// GetRegistryKeyChain get image pull keychain from (ordered):
// 1. username and secrets labels
// 2. cri request
// 3. docker config
// 4. k8s docker config secret
func GetRegistryKeyChain(host, ref string, labels map[string]string) *PassKeyChain {
	kc := FromLabels(labels)
	if kc != nil {
		return kc
	}

	// TODO: Handle error
	kc, _ = FromCRI(host, ref)
	if kc != nil {
		return kc
	}

	kc = FromDockerConfig(host)
	if kc != nil {
		return kc
	}

	return FromKubeSecretDockerConfig(host)
}

func GetKeyChainByRef(ref string, labels map[string]string) (*PassKeyChain, error) {
	named, err := docker.ParseDockerRef(ref)
	if err != nil {
		return nil, errors.Wrapf(err, "parse ref %s", ref)
	}

	host := docker.Domain(named)
	keychain := GetRegistryKeyChain(host, ref, labels)

	return keychain, nil
}

func (kc PassKeyChain) Resolve(target authn.Resource) (authn.Authenticator, error) {
	return authn.FromConfig(kc.toAuthConfig()), nil
}

// toAuthConfig convert PassKeyChain to authn.AuthConfig when kc is token based,
// RegistryToken is preferred to
func (kc PassKeyChain) toAuthConfig() authn.AuthConfig {
	if kc.TokenBase() {
		return authn.AuthConfig{
			RegistryToken: kc.Password,
		}
	}
	return authn.AuthConfig{
		Username: kc.Username,
		Password: kc.Password,
	}
}