Merge pull request #64597 from wteiken/add_review_annotations2

Automatic merge from submit-queue (batch tested with PRs 64597, 67854, 67734, 67917, 67688). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Allow ImageReview backend to add audit annotations.

**What this PR does / why we need it**: 
This can be used to create annotations that will allow auditing of the created 
pods.

The change also introduces "fail open" audit annotations in addition to the
previously existing pod annotation for fail open.  The pod annotations for 
fail open will be deprecated soon.


**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #

**Special notes for your reviewer**:

**Release note**:
```release-note
Allow ImageReview backend to return annotations to be added to the created pod.
```
This commit is contained in:
Kubernetes Submit Queue 2018-08-27 22:18:06 -07:00 committed by GitHub
commit 583dd0ff6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 464 additions and 117 deletions

View File

@ -56,7 +56,7 @@ type ImageReviewContainerSpec struct {
// In future, we may add command line overrides, exec health check command lines, and so on. // In future, we may add command line overrides, exec health check command lines, and so on.
} }
// ImageReviewStatus is the result of the token authentication request. // ImageReviewStatus is the result of the review for the pod creation request.
type ImageReviewStatus struct { type ImageReviewStatus struct {
// Allowed indicates that all images were allowed to be run. // Allowed indicates that all images were allowed to be run.
Allowed bool Allowed bool
@ -64,4 +64,9 @@ type ImageReviewStatus struct {
// may contain a short description of what is wrong. Kubernetes // may contain a short description of what is wrong. Kubernetes
// may truncate excessively long errors when displaying to the user. // may truncate excessively long errors when displaying to the user.
Reason string Reason string
// AuditAnnotations will be added to the attributes object of the
// admission controller request using 'AddAnnotation'. The keys should
// be prefix-less (i.e., the admission controller will add an
// appropriate prefix).
AuditAnnotations map[string]string
} }

View File

@ -158,6 +158,7 @@ func Convert_imagepolicy_ImageReviewSpec_To_v1alpha1_ImageReviewSpec(in *imagepo
func autoConvert_v1alpha1_ImageReviewStatus_To_imagepolicy_ImageReviewStatus(in *v1alpha1.ImageReviewStatus, out *imagepolicy.ImageReviewStatus, s conversion.Scope) error { func autoConvert_v1alpha1_ImageReviewStatus_To_imagepolicy_ImageReviewStatus(in *v1alpha1.ImageReviewStatus, out *imagepolicy.ImageReviewStatus, s conversion.Scope) error {
out.Allowed = in.Allowed out.Allowed = in.Allowed
out.Reason = in.Reason out.Reason = in.Reason
out.AuditAnnotations = *(*map[string]string)(unsafe.Pointer(&in.AuditAnnotations))
return nil return nil
} }
@ -169,6 +170,7 @@ func Convert_v1alpha1_ImageReviewStatus_To_imagepolicy_ImageReviewStatus(in *v1a
func autoConvert_imagepolicy_ImageReviewStatus_To_v1alpha1_ImageReviewStatus(in *imagepolicy.ImageReviewStatus, out *v1alpha1.ImageReviewStatus, s conversion.Scope) error { func autoConvert_imagepolicy_ImageReviewStatus_To_v1alpha1_ImageReviewStatus(in *imagepolicy.ImageReviewStatus, out *v1alpha1.ImageReviewStatus, s conversion.Scope) error {
out.Allowed = in.Allowed out.Allowed = in.Allowed
out.Reason = in.Reason out.Reason = in.Reason
out.AuditAnnotations = *(*map[string]string)(unsafe.Pointer(&in.AuditAnnotations))
return nil return nil
} }

View File

@ -30,7 +30,7 @@ func (in *ImageReview) DeepCopyInto(out *ImageReview) {
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec) in.Spec.DeepCopyInto(&out.Spec)
out.Status = in.Status in.Status.DeepCopyInto(&out.Status)
return return
} }
@ -99,6 +99,13 @@ func (in *ImageReviewSpec) DeepCopy() *ImageReviewSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageReviewStatus) DeepCopyInto(out *ImageReviewStatus) { func (in *ImageReviewStatus) DeepCopyInto(out *ImageReviewStatus) {
*out = *in *out = *in
if in.AuditAnnotations != nil {
in, out := &in.AuditAnnotations, &out.AuditAnnotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return return
} }

View File

@ -46,6 +46,21 @@ import (
// PluginName indicates name of admission plugin. // PluginName indicates name of admission plugin.
const PluginName = "ImagePolicyWebhook" const PluginName = "ImagePolicyWebhook"
// AuditKeyPrefix is used as the prefix for all audit keys handled by this
// pluggin. Some well known suffixes are listed below.
var AuditKeyPrefix = strings.ToLower(PluginName) + ".image-policy.k8s.io/"
const (
// ImagePolicyFailedOpenKeySuffix in an annotation indicates the image
// review failed open when the image policy webhook backend connection
// failed.
ImagePolicyFailedOpenKeySuffix string = "failed-open"
// ImagePolicyAuditRequiredKeySuffix in an annotation indicates the pod
// should be audited.
ImagePolicyAuditRequiredKeySuffix string = "audit-required"
)
var ( var (
groupVersions = []schema.GroupVersion{v1alpha1.SchemeGroupVersion} groupVersions = []schema.GroupVersion{v1alpha1.SchemeGroupVersion}
) )
@ -97,12 +112,15 @@ func (a *Plugin) webhookError(pod *api.Pod, attributes admission.Attributes, err
if err != nil { if err != nil {
glog.V(2).Infof("error contacting webhook backend: %s", err) glog.V(2).Infof("error contacting webhook backend: %s", err)
if a.defaultAllow { if a.defaultAllow {
attributes.AddAnnotation(AuditKeyPrefix+ImagePolicyFailedOpenKeySuffix, "true")
// TODO(wteiken): Remove the annotation code for the 1.13 release
annotations := pod.GetAnnotations() annotations := pod.GetAnnotations()
if annotations == nil { if annotations == nil {
annotations = make(map[string]string) annotations = make(map[string]string)
} }
annotations[api.ImagePolicyFailedOpenKey] = "true" annotations[api.ImagePolicyFailedOpenKey] = "true"
pod.ObjectMeta.SetAnnotations(annotations) pod.ObjectMeta.SetAnnotations(annotations)
glog.V(2).Infof("resource allowed in spite of webhook backend failure") glog.V(2).Infof("resource allowed in spite of webhook backend failure")
return nil return nil
} }
@ -174,13 +192,17 @@ func (a *Plugin) admitPod(pod *api.Pod, attributes admission.Attributes, review
a.responseCache.Add(string(cacheKey), review.Status, a.statusTTL(review.Status)) a.responseCache.Add(string(cacheKey), review.Status, a.statusTTL(review.Status))
} }
for k, v := range review.Status.AuditAnnotations {
if err := attributes.AddAnnotation(AuditKeyPrefix+k, v); err != nil {
glog.Warningf("failed to set admission audit annotation %s to %s: %v", AuditKeyPrefix+k, v, err)
}
}
if !review.Status.Allowed { if !review.Status.Allowed {
if len(review.Status.Reason) > 0 { if len(review.Status.Reason) > 0 {
return fmt.Errorf("image policy webhook backend denied one or more images: %s", review.Status.Reason) return fmt.Errorf("image policy webhook backend denied one or more images: %s", review.Status.Reason)
} }
return errors.New("one or more images rejected by webhook backend") return errors.New("one or more images rejected by webhook backend")
} }
return nil return nil
} }

View File

@ -192,6 +192,7 @@ current-context: default
for _, tt := range tests { for _, tt := range tests {
// Use a closure so defer statements trigger between loop iterations. // Use a closure so defer statements trigger between loop iterations.
t.Run(tt.msg, func(t *testing.T) {
err := func() error { err := func() error {
tempfile, err := ioutil.TempFile("", "") tempfile, err := ioutil.TempFile("", "")
if err != nil { if err != nil {
@ -252,6 +253,7 @@ current-context: default
if err == nil && tt.wantErr { if err == nil && tt.wantErr {
t.Errorf("wanted an error when loading config, did not get one: %q", tt.msg) t.Errorf("wanted an error when loading config, did not get one: %q", tt.msg)
} }
})
} }
} }
@ -296,6 +298,7 @@ func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error
type status struct { type status struct {
Allowed bool `json:"allowed"` Allowed bool `json:"allowed"`
Reason string `json:"reason"` Reason string `json:"reason"`
AuditAnnotations map[string]string `json:"auditAnnotations"`
} }
resp := struct { resp := struct {
APIVersion string `json:"apiVersion"` APIVersion string `json:"apiVersion"`
@ -304,7 +307,11 @@ func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error
}{ }{
APIVersion: v1alpha1.SchemeGroupVersion.String(), APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: "ImageReview", Kind: "ImageReview",
Status: status{review.Status.Allowed, review.Status.Reason}, Status: status{
review.Status.Allowed,
review.Status.Reason,
review.Status.AuditAnnotations,
},
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp) json.NewEncoder(w).Encode(resp)
@ -320,6 +327,7 @@ func NewTestServer(s Service, cert, key, caCert []byte) (*httptest.Server, error
type mockService struct { type mockService struct {
allow bool allow bool
statusCode int statusCode int
outAnnotations map[string]string
} }
func (m *mockService) Review(r *v1alpha1.ImageReview) { func (m *mockService) Review(r *v1alpha1.ImageReview) {
@ -339,6 +347,8 @@ func (m *mockService) Review(r *v1alpha1.ImageReview) {
if !r.Status.Allowed { if !r.Status.Allowed {
r.Status.Reason = "not allowed" r.Status.Reason = "not allowed"
} }
r.Status.AuditAnnotations = m.outAnnotations
} }
func (m *mockService) Allow() { m.allow = true } func (m *mockService) Allow() { m.allow = true }
func (m *mockService) Deny() { m.allow = false } func (m *mockService) Deny() { m.allow = false }
@ -455,7 +465,7 @@ func TestTLSConfig(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
// Use a closure so defer statements trigger between loop iterations. // Use a closure so defer statements trigger between loop iterations.
func() { t.Run(tt.test, func(t *testing.T) {
service := new(mockService) service := new(mockService)
service.statusCode = 200 service.statusCode = 200
@ -502,7 +512,7 @@ func TestTLSConfig(t *testing.T) {
if err := wh.Validate(attr); err == nil { if err := wh.Validate(attr); err == nil {
t.Errorf("%s: incorrectly admitted with DenyAll policy", tt.test) t.Errorf("%s: incorrectly admitted with DenyAll policy", tt.test)
} }
}() })
} }
} }
@ -730,7 +740,7 @@ func TestContainerCombinations(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
// Use a closure so defer statements trigger between loop iterations. // Use a closure so defer statements trigger between loop iterations.
func() { t.Run(tt.test, func(t *testing.T) {
service := new(mockService) service := new(mockService)
service.statusCode = 200 service.statusCode = 200
@ -769,27 +779,41 @@ func TestContainerCombinations(t *testing.T) {
t.Errorf("%s: failed to admit: %v", tt.test, err) t.Errorf("%s: failed to admit: %v", tt.test, err)
return return
} }
}() })
} }
} }
// fakeAttributes decorate kadmission.Attributes. It's used to trace the added annotations.
type fakeAttributes struct {
admission.Attributes
annotations map[string]string
}
func (f fakeAttributes) AddAnnotation(k, v string) error {
f.annotations[k] = v
return f.Attributes.AddAnnotation(k, v)
}
func TestDefaultAllow(t *testing.T) { func TestDefaultAllow(t *testing.T) {
tests := []struct { tests := []struct {
test string test string
pod *api.Pod pod *api.Pod
wantAllowed, wantErr, defaultAllow bool defaultAllow bool
wantAllowed, wantErr, wantFailOpen bool
}{ }{
{ {
test: "DefaultAllow = true, backend unreachable, bad image", test: "DefaultAllow = true, backend unreachable, bad image",
pod: goodPod("bad"), pod: goodPod("bad"),
defaultAllow: true, defaultAllow: true,
wantAllowed: true, wantAllowed: true,
wantFailOpen: true,
}, },
{ {
test: "DefaultAllow = true, backend unreachable, good image", test: "DefaultAllow = true, backend unreachable, good image",
pod: goodPod("good"), pod: goodPod("good"),
defaultAllow: true, defaultAllow: true,
wantAllowed: true, wantAllowed: true,
wantFailOpen: true,
}, },
{ {
test: "DefaultAllow = false, backend unreachable, good image", test: "DefaultAllow = false, backend unreachable, good image",
@ -797,6 +821,7 @@ func TestDefaultAllow(t *testing.T) {
defaultAllow: false, defaultAllow: false,
wantAllowed: false, wantAllowed: false,
wantErr: true, wantErr: true,
wantFailOpen: false,
}, },
{ {
test: "DefaultAllow = false, backend unreachable, bad image", test: "DefaultAllow = false, backend unreachable, bad image",
@ -804,11 +829,12 @@ func TestDefaultAllow(t *testing.T) {
defaultAllow: false, defaultAllow: false,
wantAllowed: false, wantAllowed: false,
wantErr: true, wantErr: true,
wantFailOpen: false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
// Use a closure so defer statements trigger between loop iterations. // Use a closure so defer statements trigger between loop iterations.
func() { t.Run(tt.test, func(t *testing.T) {
service := new(mockService) service := new(mockService)
service.statusCode = 500 service.statusCode = 500
@ -826,6 +852,8 @@ func TestDefaultAllow(t *testing.T) {
} }
attr := admission.NewAttributesRecord(tt.pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, false, &user.DefaultInfo{}) attr := admission.NewAttributesRecord(tt.pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, false, &user.DefaultInfo{})
annotations := make(map[string]string)
attr = &fakeAttributes{attr, annotations}
err = wh.Validate(attr) err = wh.Validate(attr)
if tt.wantAllowed { if tt.wantAllowed {
@ -847,7 +875,23 @@ func TestDefaultAllow(t *testing.T) {
t.Errorf("%s: failed to admit: %v", tt.test, err) t.Errorf("%s: failed to admit: %v", tt.test, err)
return return
} }
}() podAnnotations := tt.pod.GetAnnotations()
if tt.wantFailOpen {
if podAnnotations == nil || podAnnotations[api.ImagePolicyFailedOpenKey] != "true" {
t.Errorf("missing expected fail open pod annotation")
}
if annotations[AuditKeyPrefix+ImagePolicyFailedOpenKeySuffix] != "true" {
t.Errorf("missing expected fail open attributes annotation")
}
} else {
if podAnnotations != nil && podAnnotations[api.ImagePolicyFailedOpenKey] == "true" {
t.Errorf("found unexpected fail open pod annotation")
}
if annotations[AuditKeyPrefix+ImagePolicyFailedOpenKeySuffix] == "true" {
t.Errorf("found unexpected fail open attributes annotation")
}
}
})
} }
} }
@ -898,7 +942,7 @@ func TestAnnotationFiltering(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
// Use a closure so defer statements trigger between loop iterations. // Use a closure so defer statements trigger between loop iterations.
func() { t.Run(tt.test, func(t *testing.T) {
service := new(annotationService) service := new(annotationService)
server, err := NewTestServer(service, serverCert, serverKey, caCert) server, err := NewTestServer(service, serverCert, serverKey, caCert)
@ -928,7 +972,94 @@ func TestAnnotationFiltering(t *testing.T) {
t.Errorf("expected annotations sent to webhook: %v to match expected: %v", service.Annotations(), tt.outAnnotations) t.Errorf("expected annotations sent to webhook: %v to match expected: %v", service.Annotations(), tt.outAnnotations)
} }
}() })
}
}
func TestReturnedAnnotationAdd(t *testing.T) {
tests := []struct {
test string
pod *api.Pod
verifierAnnotations map[string]string
expectedAnnotations map[string]string
}{
{
test: "Add valid response annotations",
pod: goodPod("good"),
verifierAnnotations: map[string]string{
"foo-test": "true",
"bar-test": "false",
},
expectedAnnotations: map[string]string{
"imagepolicywebhook.image-policy.k8s.io/foo-test": "true",
"imagepolicywebhook.image-policy.k8s.io/bar-test": "false",
},
},
{
test: "No returned annotations are ignored",
pod: goodPod("good"),
verifierAnnotations: map[string]string{},
expectedAnnotations: map[string]string{},
},
{
test: "Handles nil annotations",
pod: goodPod("good"),
verifierAnnotations: nil,
expectedAnnotations: map[string]string{},
},
{
test: "Adds annotations for bad request",
pod: &api.Pod{
Spec: api.PodSpec{
ServiceAccountName: "default",
SecurityContext: &api.PodSecurityContext{},
Containers: []api.Container{
{
Image: "bad",
SecurityContext: &api.SecurityContext{},
},
},
},
},
verifierAnnotations: map[string]string{
"foo-test": "false",
},
expectedAnnotations: map[string]string{
"imagepolicywebhook.image-policy.k8s.io/foo-test": "false",
},
},
}
for _, tt := range tests {
// Use a closure so defer statements trigger between loop iterations.
t.Run(tt.test, func(t *testing.T) {
service := new(mockService)
service.statusCode = 200
service.outAnnotations = tt.verifierAnnotations
server, err := NewTestServer(service, serverCert, serverKey, caCert)
if err != nil {
t.Errorf("%s: failed to create server: %v", tt.test, err)
return
}
defer server.Close()
wh, err := newImagePolicyWebhook(server.URL, clientCert, clientKey, caCert, 0, true)
if err != nil {
t.Errorf("%s: failed to create client: %v", tt.test, err)
return
}
pod := tt.pod
attr := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "namespace", "", api.Resource("pods").WithVersion("version"), "", admission.Create, false, &user.DefaultInfo{})
annotations := make(map[string]string)
attr = &fakeAttributes{attr, annotations}
err = wh.Validate(attr)
if !reflect.DeepEqual(annotations, tt.expectedAnnotations) {
t.Errorf("got audit annotations: %v; want: %v", annotations, tt.expectedAnnotations)
}
})
} }
} }

View File

@ -225,6 +225,28 @@ func (m *ImageReviewStatus) MarshalTo(dAtA []byte) (int, error) {
i++ i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Reason))) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Reason)))
i += copy(dAtA[i:], m.Reason) i += copy(dAtA[i:], m.Reason)
if len(m.AuditAnnotations) > 0 {
keysForAuditAnnotations := make([]string, 0, len(m.AuditAnnotations))
for k := range m.AuditAnnotations {
keysForAuditAnnotations = append(keysForAuditAnnotations, string(k))
}
github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations)
for _, k := range keysForAuditAnnotations {
dAtA[i] = 0x1a
i++
v := m.AuditAnnotations[string(k)]
mapSize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v)))
i = encodeVarintGenerated(dAtA, i, uint64(mapSize))
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(k)))
i += copy(dAtA[i:], k)
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(v)))
i += copy(dAtA[i:], v)
}
}
return i, nil return i, nil
} }
@ -303,6 +325,14 @@ func (m *ImageReviewStatus) Size() (n int) {
n += 2 n += 2
l = len(m.Reason) l = len(m.Reason)
n += 1 + l + sovGenerated(uint64(l)) n += 1 + l + sovGenerated(uint64(l))
if len(m.AuditAnnotations) > 0 {
for k, v := range m.AuditAnnotations {
_ = k
_ = v
mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v)))
n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize))
}
}
return n return n
} }
@ -367,9 +397,20 @@ func (this *ImageReviewStatus) String() string {
if this == nil { if this == nil {
return "nil" return "nil"
} }
keysForAuditAnnotations := make([]string, 0, len(this.AuditAnnotations))
for k := range this.AuditAnnotations {
keysForAuditAnnotations = append(keysForAuditAnnotations, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForAuditAnnotations)
mapStringForAuditAnnotations := "map[string]string{"
for _, k := range keysForAuditAnnotations {
mapStringForAuditAnnotations += fmt.Sprintf("%v: %v,", k, this.AuditAnnotations[k])
}
mapStringForAuditAnnotations += "}"
s := strings.Join([]string{`&ImageReviewStatus{`, s := strings.Join([]string{`&ImageReviewStatus{`,
`Allowed:` + fmt.Sprintf("%v", this.Allowed) + `,`, `Allowed:` + fmt.Sprintf("%v", this.Allowed) + `,`,
`Reason:` + fmt.Sprintf("%v", this.Reason) + `,`, `Reason:` + fmt.Sprintf("%v", this.Reason) + `,`,
`AuditAnnotations:` + mapStringForAuditAnnotations + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -905,6 +946,122 @@ func (m *ImageReviewStatus) Unmarshal(dAtA []byte) error {
} }
m.Reason = string(dAtA[iNdEx:postIndex]) m.Reason = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AuditAnnotations", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
var keykey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
keykey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return ErrInvalidLengthGenerated
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
if m.AuditAnnotations == nil {
m.AuditAnnotations = make(map[string]string)
}
if iNdEx < postIndex {
var valuekey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
valuekey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapvalue uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapvalue |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapvalue := int(stringLenmapvalue)
if intStringLenmapvalue < 0 {
return ErrInvalidLengthGenerated
}
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
if postStringIndexmapvalue > l {
return io.ErrUnexpectedEOF
}
mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
iNdEx = postStringIndexmapvalue
m.AuditAnnotations[mapkey] = mapvalue
} else {
var mapvalue string
m.AuditAnnotations[mapkey] = mapvalue
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:]) skippy, err := skipGenerated(dAtA[iNdEx:])
@ -1036,41 +1193,43 @@ func init() {
} }
var fileDescriptorGenerated = []byte{ var fileDescriptorGenerated = []byte{
// 562 bytes of a gzipped FileDescriptorProto // 607 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x4f, 0x6f, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xcf, 0x6e, 0xd3, 0x4c,
0x18, 0xc6, 0x9b, 0xee, 0x6f, 0x5d, 0x60, 0x9b, 0xe1, 0x10, 0xf5, 0x90, 0x4d, 0x45, 0x42, 0xe3, 0x14, 0xc5, 0xe3, 0xa4, 0xff, 0x32, 0xf9, 0x3e, 0x9a, 0x0e, 0x20, 0x59, 0x59, 0xb8, 0x55, 0x90,
0x80, 0xcd, 0x26, 0x84, 0x06, 0x07, 0x50, 0x83, 0x90, 0xe0, 0x00, 0x48, 0xe6, 0xb6, 0x13, 0x6e, 0x50, 0x59, 0x30, 0x43, 0x2b, 0x84, 0x0a, 0x0b, 0x50, 0x5c, 0x21, 0x95, 0x05, 0x20, 0x0d, 0xbb,
0xfa, 0x2e, 0x0d, 0x6d, 0xec, 0x28, 0x76, 0x32, 0x7a, 0xe3, 0x23, 0xf0, 0x0d, 0xf8, 0x3a, 0x3d, 0xae, 0x98, 0x38, 0x17, 0xc7, 0x24, 0x9e, 0xb1, 0x3c, 0xe3, 0x94, 0xec, 0x78, 0x02, 0xc4, 0x1b,
0xee, 0xb8, 0xd3, 0x44, 0xc3, 0x91, 0x2f, 0x81, 0xe2, 0xa4, 0x4d, 0x68, 0x41, 0xa8, 0xb7, 0xbc, 0xf0, 0x22, 0x3c, 0x40, 0x97, 0x5d, 0x76, 0x55, 0x51, 0xb3, 0xe4, 0x25, 0x90, 0xc7, 0x4e, 0x6c,
0xef, 0xeb, 0xe7, 0xf7, 0x3e, 0x79, 0x6c, 0xf4, 0x66, 0x74, 0xa6, 0x48, 0x20, 0xe9, 0x28, 0xe9, 0x92, 0x22, 0x94, 0x9d, 0xef, 0xbd, 0x73, 0x7e, 0xf7, 0xcc, 0xf1, 0xa0, 0x93, 0xd1, 0x91, 0x22,
0x43, 0x2c, 0x40, 0x83, 0xa2, 0x29, 0x88, 0x81, 0x8c, 0x69, 0x39, 0xe0, 0x51, 0x40, 0x83, 0x90, 0x81, 0xa4, 0xa3, 0xa4, 0x0f, 0xb1, 0x00, 0x0d, 0x8a, 0x4e, 0x40, 0x0c, 0x64, 0x4c, 0x8b, 0x01,
0xfb, 0x10, 0xc9, 0x71, 0xe0, 0x4d, 0x68, 0x7a, 0xc2, 0xc7, 0xd1, 0x90, 0x9f, 0x50, 0x1f, 0x04, 0x8f, 0x02, 0x1a, 0x84, 0xdc, 0x87, 0x48, 0x8e, 0x03, 0x6f, 0x4a, 0x27, 0x07, 0x7c, 0x1c, 0x0d,
0xc4, 0x5c, 0xc3, 0x80, 0x44, 0xb1, 0xd4, 0x12, 0x1f, 0x16, 0x02, 0xc2, 0xa3, 0x80, 0xd4, 0x04, 0xf9, 0x01, 0xf5, 0x41, 0x40, 0xcc, 0x35, 0x0c, 0x48, 0x14, 0x4b, 0x2d, 0xf1, 0x6e, 0x2e, 0x20,
0x64, 0x2e, 0xe8, 0x3c, 0xf2, 0x03, 0x3d, 0x4c, 0xfa, 0xc4, 0x93, 0x21, 0xf5, 0xa5, 0x2f, 0xa9, 0x3c, 0x0a, 0x48, 0x45, 0x40, 0x66, 0x82, 0xce, 0x43, 0x3f, 0xd0, 0xc3, 0xa4, 0x4f, 0x3c, 0x19,
0xd1, 0xf5, 0x93, 0x0b, 0x53, 0x99, 0xc2, 0x7c, 0x15, 0xbc, 0xce, 0x93, 0xca, 0x40, 0xc8, 0xbd, 0x52, 0x5f, 0xfa, 0x92, 0x1a, 0x5d, 0x3f, 0xf9, 0x60, 0x2a, 0x53, 0x98, 0xaf, 0x9c, 0xd7, 0x79,
0x61, 0x20, 0x20, 0x9e, 0xd0, 0x68, 0xe4, 0xe7, 0x0d, 0x45, 0x43, 0xd0, 0x9c, 0xa6, 0x2b, 0x2e, 0x5c, 0x1a, 0x08, 0xb9, 0x37, 0x0c, 0x04, 0xc4, 0x53, 0x1a, 0x8d, 0xfc, 0xac, 0xa1, 0x68, 0x08,
0x3a, 0xf4, 0x5f, 0xaa, 0x38, 0x11, 0x3a, 0x08, 0x61, 0x45, 0xf0, 0xf4, 0x7f, 0x02, 0xe5, 0x0d, 0x9a, 0xd3, 0xc9, 0x92, 0x8b, 0x0e, 0xfd, 0x9b, 0x2a, 0x4e, 0x84, 0x0e, 0x42, 0x58, 0x12, 0x3c,
0x21, 0xe4, 0xcb, 0xba, 0xee, 0xf7, 0x26, 0x6a, 0xbf, 0xcd, 0x7f, 0x93, 0x41, 0x1a, 0xc0, 0x25, 0xf9, 0x97, 0x40, 0x79, 0x43, 0x08, 0xf9, 0xa2, 0xae, 0xfb, 0xad, 0x8e, 0x5a, 0xaf, 0xb2, 0x6b,
0xfe, 0x84, 0x76, 0x73, 0x4f, 0x03, 0xae, 0xb9, 0x6d, 0x1d, 0x59, 0xc7, 0xed, 0xd3, 0xc7, 0xa4, 0x32, 0x98, 0x04, 0x70, 0x86, 0xdf, 0xa3, 0xad, 0xcc, 0xd3, 0x80, 0x6b, 0x6e, 0x5b, 0x7b, 0xd6,
0x4a, 0x64, 0x81, 0x26, 0xd1, 0xc8, 0xcf, 0x1b, 0x8a, 0xe4, 0xa7, 0x49, 0x7a, 0x42, 0x3e, 0xf4, 0x7e, 0xeb, 0xf0, 0x11, 0x29, 0x13, 0x99, 0xa3, 0x49, 0x34, 0xf2, 0xb3, 0x86, 0x22, 0xd9, 0x69,
0x3f, 0x83, 0xa7, 0xdf, 0x81, 0xe6, 0x2e, 0x9e, 0xde, 0x1c, 0x36, 0xb2, 0x9b, 0x43, 0x54, 0xf5, 0x32, 0x39, 0x20, 0x6f, 0xfb, 0x1f, 0xc1, 0xd3, 0xaf, 0x41, 0x73, 0x17, 0x9f, 0x5f, 0xed, 0xd6,
0xd8, 0x82, 0x8a, 0x19, 0xda, 0x54, 0x11, 0x78, 0x76, 0x73, 0x85, 0xfe, 0xd7, 0xbc, 0x49, 0xcd, 0xd2, 0xab, 0x5d, 0x54, 0xf6, 0xd8, 0x9c, 0x8a, 0x19, 0x5a, 0x53, 0x11, 0x78, 0x76, 0x7d, 0x89,
0xdd, 0xc7, 0x08, 0x3c, 0xf7, 0x56, 0x49, 0xdf, 0xcc, 0x2b, 0x66, 0x58, 0xf8, 0x1c, 0x6d, 0x2b, 0x7e, 0x63, 0xde, 0xa4, 0xe2, 0xee, 0x5d, 0x04, 0x9e, 0xfb, 0x5f, 0x41, 0x5f, 0xcb, 0x2a, 0x66,
0xcd, 0x75, 0xa2, 0xec, 0x0d, 0x43, 0x3d, 0x5d, 0x8b, 0x6a, 0x94, 0xee, 0x9d, 0x92, 0xbb, 0x5d, 0x58, 0xf8, 0x14, 0x6d, 0x28, 0xcd, 0x75, 0xa2, 0xec, 0x86, 0xa1, 0x1e, 0xae, 0x44, 0x35, 0x4a,
0xd4, 0xac, 0x24, 0x76, 0x5f, 0x22, 0xbb, 0x76, 0xf8, 0x95, 0x14, 0x9a, 0xe7, 0x11, 0xe4, 0xdb, 0xf7, 0x56, 0xc1, 0xdd, 0xc8, 0x6b, 0x56, 0x10, 0xbb, 0x2f, 0x90, 0x5d, 0x39, 0x7c, 0x2c, 0x85,
0xf1, 0x7d, 0xb4, 0x65, 0xe8, 0x26, 0xaa, 0x96, 0x7b, 0xbb, 0x44, 0x6c, 0x15, 0x82, 0x62, 0xd6, 0xe6, 0x59, 0x04, 0xd9, 0x76, 0x7c, 0x0f, 0xad, 0x1b, 0xba, 0x89, 0xaa, 0xe9, 0xfe, 0x5f, 0x20,
0xfd, 0xd5, 0x44, 0x7b, 0x4b, 0x3f, 0x81, 0x43, 0x84, 0xbc, 0x39, 0x49, 0xd9, 0xd6, 0xd1, 0xc6, 0xd6, 0x73, 0x41, 0x3e, 0xeb, 0xfe, 0xaa, 0xa3, 0xed, 0x85, 0x4b, 0xe0, 0x10, 0x21, 0x6f, 0x46,
0x71, 0xfb, 0xf4, 0xd9, 0x3a, 0xa6, 0xff, 0xf0, 0x51, 0x25, 0xbe, 0x68, 0x2b, 0x56, 0x5b, 0x80, 0x52, 0xb6, 0xb5, 0xd7, 0xd8, 0x6f, 0x1d, 0x3e, 0x5d, 0xc5, 0xf4, 0x1f, 0x3e, 0xca, 0xc4, 0xe7,
0xbf, 0xa0, 0x36, 0x17, 0x42, 0x6a, 0xae, 0x03, 0x29, 0x94, 0xdd, 0x34, 0xfb, 0x7a, 0xeb, 0x46, 0x6d, 0xc5, 0x2a, 0x0b, 0xf0, 0x27, 0xd4, 0xe2, 0x42, 0x48, 0xcd, 0x75, 0x20, 0x85, 0xb2, 0xeb,
0x4f, 0x7a, 0x15, 0xe3, 0xb5, 0xd0, 0xf1, 0xc4, 0xbd, 0x5b, 0xee, 0x6d, 0xd7, 0x26, 0xac, 0xbe, 0x66, 0x5f, 0x6f, 0xd5, 0xe8, 0x49, 0xaf, 0x64, 0xbc, 0x14, 0x3a, 0x9e, 0xba, 0xb7, 0x8b, 0xbd,
0x0a, 0x53, 0xd4, 0x12, 0x3c, 0x04, 0x15, 0x71, 0x0f, 0xcc, 0xe5, 0xb4, 0xdc, 0x83, 0x52, 0xd4, 0xad, 0xca, 0x84, 0x55, 0x57, 0x61, 0x8a, 0x9a, 0x82, 0x87, 0xa0, 0x22, 0xee, 0x81, 0xf9, 0x39,
0x7a, 0x3f, 0x1f, 0xb0, 0xea, 0x4c, 0xe7, 0x05, 0xda, 0x5f, 0x5e, 0x83, 0xf7, 0xd1, 0xc6, 0x08, 0x4d, 0x77, 0xa7, 0x10, 0x35, 0xdf, 0xcc, 0x06, 0xac, 0x3c, 0xd3, 0x79, 0x8e, 0xda, 0x8b, 0x6b,
0x26, 0x45, 0xc8, 0x2c, 0xff, 0xc4, 0xf7, 0xd0, 0x56, 0xca, 0xc7, 0x09, 0x98, 0x57, 0xd4, 0x62, 0x70, 0x1b, 0x35, 0x46, 0x30, 0xcd, 0x43, 0x66, 0xd9, 0x27, 0xbe, 0x83, 0xd6, 0x27, 0x7c, 0x9c,
0x45, 0xf1, 0xbc, 0x79, 0x66, 0x75, 0x2f, 0xd0, 0xc1, 0xca, 0xdd, 0xe2, 0x87, 0x68, 0x87, 0x8f, 0x80, 0x79, 0x45, 0x4d, 0x96, 0x17, 0xcf, 0xea, 0x47, 0x56, 0xf7, 0x7b, 0x1d, 0xed, 0x2c, 0xfd,
0xc7, 0xf2, 0x12, 0x06, 0x06, 0xb2, 0xeb, 0xee, 0x95, 0x1e, 0x76, 0x7a, 0x45, 0x9b, 0xcd, 0xe7, 0x5c, 0xfc, 0x00, 0x6d, 0xf2, 0xf1, 0x58, 0x9e, 0xc1, 0xc0, 0x50, 0xb6, 0xdc, 0xed, 0xc2, 0xc4,
0xf8, 0x01, 0xda, 0x8e, 0x81, 0x2b, 0x29, 0x0a, 0x74, 0xf5, 0x2c, 0x98, 0xe9, 0xb2, 0x72, 0xea, 0x66, 0x2f, 0x6f, 0xb3, 0xd9, 0x1c, 0xdf, 0x47, 0x1b, 0x31, 0x70, 0x25, 0x45, 0xce, 0x2e, 0xdf,
0x92, 0xe9, 0xcc, 0x69, 0x5c, 0xcd, 0x9c, 0xc6, 0xf5, 0xcc, 0x69, 0x7c, 0xcd, 0x1c, 0x6b, 0x9a, 0x05, 0x33, 0x5d, 0x56, 0x4c, 0xf1, 0x17, 0x0b, 0xb5, 0x79, 0x32, 0x08, 0x74, 0xc5, 0xae, 0xdd,
0x39, 0xd6, 0x55, 0xe6, 0x58, 0xd7, 0x99, 0x63, 0xfd, 0xc8, 0x1c, 0xeb, 0xdb, 0x4f, 0xa7, 0x71, 0x30, 0xc9, 0x9e, 0xac, 0xfe, 0xfc, 0x48, 0x6f, 0x01, 0x95, 0x07, 0x6c, 0x17, 0xcb, 0xdb, 0x8b,
0xbe, 0x3b, 0xcf, 0xf2, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdb, 0xb6, 0xff, 0xb4, 0xa2, 0x04, 0x63, 0xb6, 0xb4, 0xbb, 0x73, 0x8c, 0xee, 0xde, 0x08, 0x59, 0x25, 0x3e, 0x97, 0x9c, 0x5f, 0x3b,
0x00, 0x00, 0xb5, 0x8b, 0x6b, 0xa7, 0x76, 0x79, 0xed, 0xd4, 0x3e, 0xa7, 0x8e, 0x75, 0x9e, 0x3a, 0xd6, 0x45,
0xea, 0x58, 0x97, 0xa9, 0x63, 0xfd, 0x48, 0x1d, 0xeb, 0xeb, 0x4f, 0xa7, 0x76, 0xba, 0x35, 0xbb,
0xc8, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x44, 0x16, 0x48, 0xa2, 0x79, 0x05, 0x00, 0x00,
} }

View File

@ -65,7 +65,7 @@ message ImageReviewSpec {
optional string namespace = 3; optional string namespace = 3;
} }
// ImageReviewStatus is the result of the token authentication request. // ImageReviewStatus is the result of the review for the pod creation request.
message ImageReviewStatus { message ImageReviewStatus {
// Allowed indicates that all images were allowed to be run. // Allowed indicates that all images were allowed to be run.
optional bool allowed = 1; optional bool allowed = 1;
@ -75,5 +75,12 @@ message ImageReviewStatus {
// may truncate excessively long errors when displaying to the user. // may truncate excessively long errors when displaying to the user.
// +optional // +optional
optional string reason = 2; optional string reason = 2;
// AuditAnnotations will be added to the attributes object of the
// admission controller request using 'AddAnnotation'. The keys should
// be prefix-less (i.e., the admission controller will add an
// appropriate prefix).
// +optional
map<string, string> auditAnnotations = 3;
} }

View File

@ -62,7 +62,7 @@ type ImageReviewContainerSpec struct {
// In future, we may add command line overrides, exec health check command lines, and so on. // In future, we may add command line overrides, exec health check command lines, and so on.
} }
// ImageReviewStatus is the result of the token authentication request. // ImageReviewStatus is the result of the review for the pod creation request.
type ImageReviewStatus struct { type ImageReviewStatus struct {
// Allowed indicates that all images were allowed to be run. // Allowed indicates that all images were allowed to be run.
Allowed bool `json:"allowed" protobuf:"varint,1,opt,name=allowed"` Allowed bool `json:"allowed" protobuf:"varint,1,opt,name=allowed"`
@ -71,4 +71,10 @@ type ImageReviewStatus struct {
// may truncate excessively long errors when displaying to the user. // may truncate excessively long errors when displaying to the user.
// +optional // +optional
Reason string `json:"reason,omitempty" protobuf:"bytes,2,opt,name=reason"` Reason string `json:"reason,omitempty" protobuf:"bytes,2,opt,name=reason"`
// AuditAnnotations will be added to the attributes object of the
// admission controller request using 'AddAnnotation'. The keys should
// be prefix-less (i.e., the admission controller will add an
// appropriate prefix).
// +optional
AuditAnnotations map[string]string `json:"auditAnnotations,omitempty" protobuf:"bytes,3,rep,name=auditAnnotations"`
} }

View File

@ -58,9 +58,10 @@ func (ImageReviewSpec) SwaggerDoc() map[string]string {
} }
var map_ImageReviewStatus = map[string]string{ var map_ImageReviewStatus = map[string]string{
"": "ImageReviewStatus is the result of the token authentication request.", "": "ImageReviewStatus is the result of the review for the pod creation request.",
"allowed": "Allowed indicates that all images were allowed to be run.", "allowed": "Allowed indicates that all images were allowed to be run.",
"reason": "Reason should be empty unless Allowed is false in which case it may contain a short description of what is wrong. Kubernetes may truncate excessively long errors when displaying to the user.", "reason": "Reason should be empty unless Allowed is false in which case it may contain a short description of what is wrong. Kubernetes may truncate excessively long errors when displaying to the user.",
"auditAnnotations": "AuditAnnotations will be added to the attributes object of the admission controller request using 'AddAnnotation'. The keys should be prefix-less (i.e., the admission controller will add an appropriate prefix).",
} }
func (ImageReviewStatus) SwaggerDoc() map[string]string { func (ImageReviewStatus) SwaggerDoc() map[string]string {

View File

@ -30,7 +30,7 @@ func (in *ImageReview) DeepCopyInto(out *ImageReview) {
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec) in.Spec.DeepCopyInto(&out.Spec)
out.Status = in.Status in.Status.DeepCopyInto(&out.Status)
return return
} }
@ -99,6 +99,13 @@ func (in *ImageReviewSpec) DeepCopy() *ImageReviewSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageReviewStatus) DeepCopyInto(out *ImageReviewStatus) { func (in *ImageReviewStatus) DeepCopyInto(out *ImageReviewStatus) {
*out = *in *out = *in
if in.AuditAnnotations != nil {
in, out := &in.AuditAnnotations, &out.AuditAnnotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return return
} }