mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
add dockercfg secret types
This commit is contained in:
parent
d404a17f0a
commit
be0f2d2930
@ -1859,6 +1859,15 @@ const (
|
||||
ServiceAccountTokenKey = "token"
|
||||
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||
|
||||
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||
//
|
||||
// Required fields:
|
||||
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||
|
||||
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||
DockerConfigKey = ".dockercfg"
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
|
@ -1754,6 +1754,17 @@ const (
|
||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountTokenKey = "token"
|
||||
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||
|
||||
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||
//
|
||||
// Required fields:
|
||||
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||
|
||||
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||
DockerConfigKey = ".dockercfg"
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
|
@ -1657,6 +1657,17 @@ const (
|
||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountTokenKey = "token"
|
||||
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||
|
||||
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||
//
|
||||
// Required fields:
|
||||
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||
|
||||
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||
DockerConfigKey = ".dockercfg"
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
|
@ -1734,6 +1734,17 @@ const (
|
||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountTokenKey = "token"
|
||||
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||
|
||||
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||
//
|
||||
// Required fields:
|
||||
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||
|
||||
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||
DockerConfigKey = ".dockercfg"
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
|
@ -1754,6 +1754,17 @@ const (
|
||||
ServiceAccountUIDKey = "kubernetes.io/service-account.uid"
|
||||
// ServiceAccountTokenKey is the key of the required data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountTokenKey = "token"
|
||||
// ServiceAccountKubeconfigKey is the key of the optional kubeconfig data for SecretTypeServiceAccountToken secrets
|
||||
ServiceAccountKubeconfigKey = "kubernetes.kubeconfig"
|
||||
|
||||
// SecretTypeDockercfg contains a dockercfg file that follows the same format rules as ~/.dockercfg
|
||||
//
|
||||
// Required fields:
|
||||
// - Secret.Data[".dockercfg"] - a serialized ~/.dockercfg file
|
||||
SecretTypeDockercfg SecretType = "kubernetes.io/dockercfg"
|
||||
|
||||
// DockerConfigKey is the key of the required data for SecretTypeDockercfg secrets
|
||||
DockerConfigKey = ".dockercfg"
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package validation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"path"
|
||||
@ -1295,6 +1296,18 @@ func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
|
||||
}
|
||||
case api.SecretTypeOpaque, "":
|
||||
// no-op
|
||||
case api.SecretTypeDockercfg:
|
||||
dockercfgBytes, exists := secret.Data[api.DockerConfigKey]
|
||||
if !exists {
|
||||
allErrs = append(allErrs, errs.NewFieldRequired(fmt.Sprintf("data[%s]", api.DockerConfigKey)))
|
||||
break
|
||||
}
|
||||
|
||||
// make sure that the content is well-formed json.
|
||||
if err := json.Unmarshal(dockercfgBytes, &map[string]interface{}{}); err != nil {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid(fmt.Sprintf("data[%s]", api.DockerConfigKey), "<secret contents redacted>", err.Error()))
|
||||
}
|
||||
|
||||
default:
|
||||
// no-op
|
||||
}
|
||||
|
@ -2949,6 +2949,48 @@ func TestValidateSecret(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDockerConfigSecret(t *testing.T) {
|
||||
validDockerSecret := func() api.Secret {
|
||||
return api.Secret{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
|
||||
Type: api.SecretTypeDockercfg,
|
||||
Data: map[string][]byte{
|
||||
api.DockerConfigKey: []byte(`{"https://index.docker.io/v1/": {"auth": "Y2x1ZWRyb29sZXIwMDAxOnBhc3N3b3Jk","email": "fake@example.com"}}`),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
missingDockerConfigKey = validDockerSecret()
|
||||
emptyDockerConfigKey = validDockerSecret()
|
||||
invalidDockerConfigKey = validDockerSecret()
|
||||
)
|
||||
|
||||
delete(missingDockerConfigKey.Data, api.DockerConfigKey)
|
||||
emptyDockerConfigKey.Data[api.DockerConfigKey] = []byte("")
|
||||
invalidDockerConfigKey.Data[api.DockerConfigKey] = []byte("bad")
|
||||
|
||||
tests := map[string]struct {
|
||||
secret api.Secret
|
||||
valid bool
|
||||
}{
|
||||
"valid": {validDockerSecret(), true},
|
||||
"missing dockercfg": {missingDockerConfigKey, false},
|
||||
"empty dockercfg": {emptyDockerConfigKey, false},
|
||||
"invalid dockercfg": {invalidDockerConfigKey, false},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
errs := ValidateSecret(&tc.secret)
|
||||
if tc.valid && len(errs) > 0 {
|
||||
t.Errorf("%v: Unexpected error: %v", name, errs)
|
||||
}
|
||||
if !tc.valid && len(errs) == 0 {
|
||||
t.Errorf("%v: Unexpected non-error", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEndpoints(t *testing.T) {
|
||||
successCases := map[string]api.Endpoints{
|
||||
"simple endpoint": {
|
||||
|
@ -147,17 +147,17 @@ func readDockerConfigFileFromBytes(contents []byte) (cfg DockerConfig, err error
|
||||
return
|
||||
}
|
||||
|
||||
// dockerConfigEntryWithAuth is used solely for deserializing the Auth field
|
||||
// DockerConfigEntryWithAuth is used solely for deserializing the Auth field
|
||||
// into a dockerConfigEntry during JSON deserialization.
|
||||
type dockerConfigEntryWithAuth struct {
|
||||
Username string
|
||||
Password string
|
||||
Email string
|
||||
Auth string
|
||||
type DockerConfigEntryWithAuth struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Auth string `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
func (ident *DockerConfigEntry) UnmarshalJSON(data []byte) error {
|
||||
var tmp dockerConfigEntryWithAuth
|
||||
var tmp DockerConfigEntryWithAuth
|
||||
err := json.Unmarshal(data, &tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -194,3 +194,16 @@ func decodeDockerConfigFieldAuth(field string) (username, password string, err e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ident DockerConfigEntry) ConvertToDockerConfigCompatible() DockerConfigEntryWithAuth {
|
||||
ret := DockerConfigEntryWithAuth{ident.Username, ident.Password, ident.Email, ""}
|
||||
ret.Auth = encodeDockerConfigFieldAuth(ident.Username, ident.Password)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func encodeDockerConfigFieldAuth(username, password string) string {
|
||||
fieldValue := username + ":" + password
|
||||
|
||||
return base64.StdEncoding.EncodeToString([]byte(fieldValue))
|
||||
}
|
||||
|
@ -166,3 +166,33 @@ func TestDecodeDockerConfigFieldAuth(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDockerConfigEntryJSONCompatibleEncode(t *testing.T) {
|
||||
tests := []struct {
|
||||
input DockerConfigEntry
|
||||
expect []byte
|
||||
}{
|
||||
// simple case, just decode the fields
|
||||
{
|
||||
expect: []byte(`{"username":"foo","password":"bar","email":"foo@example.com","auth":"Zm9vOmJhcg=="}`),
|
||||
input: DockerConfigEntry{
|
||||
Username: "foo",
|
||||
Password: "bar",
|
||||
Email: "foo@example.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
toEncode := tt.input.ConvertToDockerConfigCompatible()
|
||||
|
||||
actual, err := json.Marshal(toEncode)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error: %v", i, err)
|
||||
}
|
||||
|
||||
if string(tt.expect) != string(actual) {
|
||||
t.Errorf("case %d: expected %v, got %v", i, string(tt.expect), string(actual))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user