Skip to content

Commit

Permalink
ensure secret pulled images
Browse files Browse the repository at this point in the history
Signed-off-by: Mike Brown <brownwm@us.ibm.com>
  • Loading branch information
mikebrow committed Mar 3, 2022
1 parent 16c9d59 commit f680c5b
Show file tree
Hide file tree
Showing 15 changed files with 410 additions and 54 deletions.
9 changes: 9 additions & 0 deletions pkg/features/kube_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,14 @@ const (
//
// Stop auto-generation of secret-based service account tokens.
LegacyServiceAccountTokenNoAutoGeneration featuregate.Feature = "LegacyServiceAccountTokenNoAutoGeneration"

// owner: @mikebrow
// kep: http://kep.k8s.io/2535
// alpha: v1.24
//
// Enables kubelet to ensure images pulled with pod imagePullSecrets are authenticated
// by other pods that do not have the same credentials.
KubeletEnsureSecretPulledImages featuregate.Feature = "KubeletEnsureSecretPulledImages"
)

func init() {
Expand Down Expand Up @@ -947,6 +955,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
RecoverVolumeExpansionFailure: {Default: false, PreRelease: featuregate.Alpha},
GRPCContainerProbe: {Default: false, PreRelease: featuregate.Alpha},
LegacyServiceAccountTokenNoAutoGeneration: {Default: true, PreRelease: featuregate.Beta},
KubeletEnsureSecretPulledImages: {Default: false, PreRelease: featuregate.Alpha},

// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
Expand Down
9 changes: 9 additions & 0 deletions pkg/kubelet/container/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/json"
"fmt"
"hash/fnv"
"strconv"
"strings"

"k8s.io/klog/v2"
Expand Down Expand Up @@ -107,6 +108,14 @@ func HashContainer(container *v1.Container) uint64 {
return uint64(hash.Sum32())
}

// HashAuth - returns a hash code for a CRI pull image auth
func HashAuth(auth *runtimeapi.AuthConfig) string {
hash := fnv.New64a()
authJSON, _ := json.Marshal(auth)
hashutil.DeepHashObject(hash, authJSON)
return strconv.FormatUint(hash.Sum64(), 16)
}

// envVarsToMap constructs a map of environment name to value from a slice
// of env vars.
func envVarsToMap(envs []EnvVar) map[string]string {
Expand Down
50 changes: 50 additions & 0 deletions pkg/kubelet/container/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
"k8s.io/kubernetes/pkg/features"
)

Expand Down Expand Up @@ -699,3 +700,52 @@ func TestShouldRecordEvent(t *testing.T) {
_, actual = innerEventRecorder.shouldRecordEvent(nilObj)
assert.Equal(t, false, actual, "should not panic if the typed nil was used, see https://github.com/kubernetes/kubernetes/issues/95552")
}

func TestHashAuth(t *testing.T) {
testUser := "username"
testPasswd := "password"
testAuth := testUser + ":" + testPasswd
testServer := "https://registry-1.io"
testIdentityToken := "kas9Da81Dfa8"
testRegistryToken :=
`eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w`

testCases := []struct {
auth *runtimeapi.AuthConfig
expectedHash string
}{
{
auth: &runtimeapi.AuthConfig{
IdentityToken: testIdentityToken},
expectedHash: "4d3e035376aaa6fe",
},
{
auth: &runtimeapi.AuthConfig{
Username: testUser,
Password: testPasswd,
ServerAddress: testServer},
expectedHash: "deed1b4ea7ff40f9",
},
{
auth: &runtimeapi.AuthConfig{
Auth: testAuth,
ServerAddress: testServer},
expectedHash: "f5017bcbcc0fbffc",
},
{
auth: &runtimeapi.AuthConfig{
ServerAddress: testServer,
RegistryToken: testRegistryToken},
expectedHash: "28256605b2151d68",
},
{
auth: &runtimeapi.AuthConfig{},
expectedHash: "42a21bc689278e90",
},
}

for _, tc := range testCases {
hashVal := HashAuth(tc.auth)
assert.Equal(t, tc.expectedHash, hashVal, "the hash value here should not be changed.")
}
}
5 changes: 3 additions & 2 deletions pkg/kubelet/container/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ type StreamingRuntime interface {
// ImageService interfaces allows to work with image service.
type ImageService interface {
// PullImage pulls an image from the network to local storage using the supplied
// secrets if necessary. It returns a reference (digest or ID) to the pulled image.
PullImage(image ImageSpec, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, error)
// secrets if necessary. It returns a reference (digest or ID) to the pulled image
// and if applicable a hash for the auth used to successfully pull the image.
PullImage(image ImageSpec, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error)
// GetImageRef gets the reference (digest or ID) of the image which has already been in
// the local storage. It returns ("", nil) if the image isn't in the local storage.
GetImageRef(image ImageSpec) (string, error)
Expand Down
4 changes: 2 additions & 2 deletions pkg/kubelet/container/testing/fake_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ func (f *FakeRuntime) GetContainerLogs(_ context.Context, pod *v1.Pod, container
return f.Err
}

func (f *FakeRuntime) PullImage(image kubecontainer.ImageSpec, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, error) {
func (f *FakeRuntime) PullImage(image kubecontainer.ImageSpec, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error) {
f.Lock()
defer f.Unlock()

Expand All @@ -305,7 +305,7 @@ func (f *FakeRuntime) PullImage(image kubecontainer.ImageSpec, pullSecrets []v1.
}
f.ImageList = append(f.ImageList, i)
}
return image.Image, f.Err
return image.Image, "", f.Err
}

func (f *FakeRuntime) GetImageRef(image kubecontainer.ImageSpec) (string, error) {
Expand Down
30 changes: 24 additions & 6 deletions pkg/kubelet/container/testing/runtime_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions pkg/kubelet/cri/remote/remote_runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ func TestVersion(t *testing.T) {
r := createRemoteRuntimeService(endpoint, t)
version, err := r.Version(apitest.FakeVersion)
assert.NoError(t, err)
assert.Equal(t, apitest.FakeVersion, version.Version)
assert.Equal(t, apitest.FakeRuntimeName, version.RuntimeName)
if version != nil { // TODO: (Mike Brown) refactor for startup timing issues
assert.Equal(t, apitest.FakeVersion, version.Version)
assert.Equal(t, apitest.FakeRuntimeName, version.RuntimeName)
}
}
4 changes: 2 additions & 2 deletions pkg/kubelet/images/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ type throttledImageService struct {
limiter flowcontrol.RateLimiter
}

func (ts throttledImageService) PullImage(image kubecontainer.ImageSpec, secrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, error) {
func (ts throttledImageService) PullImage(image kubecontainer.ImageSpec, secrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error) {
if ts.limiter.TryAccept() {
return ts.ImageService.PullImage(image, secrets, podSandboxConfig)
}
return "", fmt.Errorf("pull QPS exceeded")
return "", "", fmt.Errorf("pull QPS exceeded")
}
Loading

0 comments on commit f680c5b

Please sign in to comment.