diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go
index cfea0550661..d6d15adb583 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/types.go
@@ -215,10 +215,17 @@ type GroupResources struct {
 	// The empty string represents the core API group.
 	// +optional
 	Group string
-	// Resources is a list of resources within the API group.
-	// Any empty list implies every resource kind in the API group.
+	// Resources is a list of resources within the API group. Subresources are
+	// matched using a "/" to indicate the subresource. For example, "pods/logs"
+	// would match request to the logs subresource of pods. The top level resource
+	// does not match subresources, "pods" doesn't match "pods/logs".
 	// +optional
 	Resources []string
+	// ResourceNames is a list of resource instance names that the policy matches.
+	// Using this field requires Resources to be specified.
+	// An empty list implies that every instance of the resource is matched.
+	// +optional
+	ResourceNames []string
 }
 
 // ObjectReference contains enough information to let you inspect or modify the referred object.
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go
index f93ffe51605..8017f66ea79 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go
@@ -297,6 +297,21 @@ func (m *GroupResources) MarshalTo(dAtA []byte) (int, error) {
 			i += copy(dAtA[i:], s)
 		}
 	}
+	if len(m.ResourceNames) > 0 {
+		for _, s := range m.ResourceNames {
+			dAtA[i] = 0x1a
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			dAtA[i] = uint8(l)
+			i++
+			i += copy(dAtA[i:], s)
+		}
+	}
 	return i, nil
 }
 
@@ -631,6 +646,12 @@ func (m *GroupResources) Size() (n int) {
 			n += 1 + l + sovGenerated(uint64(l))
 		}
 	}
+	if len(m.ResourceNames) > 0 {
+		for _, s := range m.ResourceNames {
+			l = len(s)
+			n += 1 + l + sovGenerated(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -780,6 +801,7 @@ func (this *GroupResources) String() string {
 	s := strings.Join([]string{`&GroupResources{`,
 		`Group:` + fmt.Sprintf("%v", this.Group) + `,`,
 		`Resources:` + fmt.Sprintf("%v", this.Resources) + `,`,
+		`ResourceNames:` + fmt.Sprintf("%v", this.ResourceNames) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -1523,6 +1545,35 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error {
 			}
 			m.Resources = append(m.Resources, string(dAtA[iNdEx:postIndex]))
 			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ResourceNames", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowGenerated
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthGenerated
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ResourceNames = append(m.ResourceNames, string(dAtA[iNdEx:postIndex]))
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipGenerated(dAtA[iNdEx:])
@@ -2384,73 +2435,75 @@ func init() {
 }
 
 var fileDescriptorGenerated = []byte{
-	// 1088 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4d, 0x6f, 0x23, 0x45,
-	0x10, 0xcd, 0xac, 0xe3, 0x8d, 0xa7, 0xb3, 0xf9, 0xd8, 0x5e, 0x04, 0xa3, 0x1c, 0xec, 0x60, 0x24,
-	0x64, 0x41, 0x98, 0x49, 0x42, 0x40, 0xcb, 0x81, 0x43, 0xac, 0x45, 0x60, 0x29, 0x84, 0xd0, 0x89,
-	0x57, 0xe2, 0xe3, 0x40, 0xdb, 0xae, 0xd8, 0x43, 0xec, 0x9e, 0xa1, 0xbb, 0xc7, 0x28, 0x37, 0x0e,
-	0x88, 0x33, 0xff, 0x08, 0x21, 0x81, 0x94, 0xe3, 0x1e, 0xf7, 0x64, 0x11, 0xf3, 0x2f, 0x72, 0x42,
-	0xdd, 0xd3, 0x33, 0x3d, 0x76, 0x36, 0xc2, 0xb9, 0xec, 0x6d, 0xba, 0xea, 0xbd, 0xd7, 0x55, 0xe5,
-	0xaa, 0x6a, 0xa3, 0xaf, 0x2f, 0x9e, 0x0a, 0x3f, 0x8c, 0x82, 0x8b, 0xa4, 0x03, 0x9c, 0x81, 0x04,
-	0x11, 0x8c, 0x81, 0xf5, 0x22, 0x1e, 0x18, 0x07, 0x8d, 0x43, 0x01, 0x7c, 0x0c, 0x3c, 0x88, 0x2f,
-	0xfa, 0xfa, 0x14, 0xd0, 0xa4, 0x17, 0xca, 0x60, 0xbc, 0x47, 0x87, 0xf1, 0x80, 0xee, 0x05, 0x7d,
-	0x60, 0xc0, 0xa9, 0x84, 0x9e, 0x1f, 0xf3, 0x48, 0x46, 0xb8, 0x91, 0x32, 0xfd, 0x9c, 0xe9, 0xc7,
-	0x17, 0x7d, 0x7d, 0xf2, 0x35, 0xd3, 0xcf, 0x98, 0x5b, 0x1f, 0xf4, 0x43, 0x39, 0x48, 0x3a, 0x7e,
-	0x37, 0x1a, 0x05, 0xfd, 0xa8, 0x1f, 0x05, 0x5a, 0xa0, 0x93, 0x9c, 0xeb, 0x93, 0x3e, 0xe8, 0xaf,
-	0x54, 0x78, 0x6b, 0xc7, 0x86, 0x14, 0xd0, 0x44, 0x0e, 0x80, 0xc9, 0xb0, 0x4b, 0x65, 0x18, 0xb1,
-	0x60, 0x7c, 0x2b, 0x8c, 0xad, 0x03, 0x8b, 0x1e, 0xd1, 0xee, 0x20, 0x64, 0xc0, 0x2f, 0x6d, 0x0e,
-	0x23, 0x90, 0xf4, 0x55, 0xac, 0xe0, 0x2e, 0x16, 0x4f, 0x98, 0x0c, 0x47, 0x70, 0x8b, 0xf0, 0xf1,
-	0xff, 0x11, 0x44, 0x77, 0x00, 0x23, 0x7a, 0x8b, 0xf7, 0xe1, 0x5d, 0xbc, 0x44, 0x86, 0xc3, 0x20,
-	0x64, 0x52, 0x48, 0x3e, 0x4f, 0xaa, 0xff, 0x55, 0x41, 0xe5, 0xcf, 0xc6, 0xc0, 0x24, 0xfe, 0x01,
-	0x55, 0x54, 0x0a, 0x3d, 0x2a, 0xa9, 0xe7, 0x6c, 0x3b, 0x8d, 0xd5, 0xfd, 0x5d, 0xdf, 0xd6, 0x3d,
-	0x57, 0xb4, 0xa5, 0x57, 0x68, 0x7f, 0xbc, 0xe7, 0x7f, 0xd5, 0xf9, 0x11, 0xba, 0xf2, 0x4b, 0x90,
-	0xb4, 0x89, 0xaf, 0x26, 0xb5, 0xa5, 0xe9, 0xa4, 0x86, 0xac, 0x8d, 0xe4, 0xaa, 0x78, 0x07, 0x95,
-	0x87, 0x30, 0x86, 0xa1, 0xf7, 0x60, 0xdb, 0x69, 0xb8, 0xcd, 0x37, 0x0d, 0xb8, 0x7c, 0xa4, 0x8c,
-	0x37, 0xd9, 0x07, 0x49, 0x41, 0xf8, 0x3b, 0xe4, 0xaa, 0x6c, 0x85, 0xa4, 0xa3, 0xd8, 0x2b, 0xe9,
-	0x80, 0xde, 0x5b, 0x2c, 0xa0, 0xb3, 0x70, 0x04, 0xcd, 0xc7, 0x46, 0xdd, 0x3d, 0xcb, 0x44, 0x88,
-	0xd5, 0xc3, 0xc7, 0x68, 0x45, 0x77, 0x4e, 0xeb, 0x99, 0xb7, 0xac, 0x83, 0x39, 0x30, 0xf0, 0x95,
-	0xc3, 0xd4, 0x7c, 0x33, 0xa9, 0xbd, 0x7d, 0x57, 0x3d, 0xe5, 0x65, 0x0c, 0xc2, 0x6f, 0xb7, 0x9e,
-	0x91, 0x4c, 0x44, 0xa5, 0x26, 0x24, 0xed, 0x83, 0x57, 0x9e, 0x4d, 0xed, 0x54, 0x19, 0x6f, 0xb2,
-	0x0f, 0x92, 0x82, 0xf0, 0x3e, 0x42, 0x1c, 0x7e, 0x4a, 0x40, 0xc8, 0x36, 0x69, 0x79, 0x0f, 0x35,
-	0x25, 0x2f, 0x1d, 0xc9, 0x3d, 0xa4, 0x80, 0xc2, 0xdb, 0x68, 0x79, 0x0c, 0xbc, 0xe3, 0xad, 0x68,
-	0xf4, 0x23, 0x83, 0x5e, 0x7e, 0x0e, 0xbc, 0x43, 0xb4, 0x07, 0x7f, 0x81, 0x96, 0x13, 0x01, 0xdc,
-	0xab, 0xe8, 0x5a, 0xbd, 0x5b, 0xa8, 0x95, 0x3f, 0xdb, 0xdb, 0xaa, 0x46, 0x6d, 0x01, 0xbc, 0xc5,
-	0xce, 0x23, 0xab, 0xa4, 0x2c, 0x44, 0x2b, 0xe0, 0x01, 0xda, 0x0c, 0x47, 0x31, 0x70, 0x11, 0x31,
-	0xd5, 0x2a, 0xca, 0xe3, 0xb9, 0xf7, 0x52, 0x7d, 0x63, 0x3a, 0xa9, 0x6d, 0xb6, 0xe6, 0x34, 0xc8,
-	0x2d, 0x55, 0xfc, 0x3e, 0x72, 0x45, 0x94, 0xf0, 0x2e, 0xb4, 0x4e, 0x84, 0x87, 0xb6, 0x4b, 0x0d,
-	0xb7, 0xb9, 0xa6, 0x7e, 0xb4, 0xd3, 0xcc, 0x48, 0xac, 0x1f, 0x9f, 0x23, 0x37, 0xd2, 0x7d, 0x45,
-	0xe0, 0xdc, 0x5b, 0xd5, 0xf1, 0x7c, 0xe2, 0x2f, 0xba, 0x1a, 0x4c, 0x9b, 0x12, 0x38, 0x07, 0x0e,
-	0xac, 0x0b, 0xe9, 0x3d, 0xb9, 0x91, 0x58, 0x69, 0x3c, 0x40, 0xeb, 0x1c, 0x44, 0x1c, 0x31, 0x01,
-	0xa7, 0x92, 0xca, 0x44, 0x78, 0x8f, 0xf4, 0x65, 0x3b, 0x8b, 0xb5, 0x5f, 0xca, 0x69, 0xe2, 0xe9,
-	0xa4, 0xb6, 0x4e, 0x66, 0x74, 0xc8, 0x9c, 0x2e, 0xa6, 0x68, 0xcd, 0xfc, 0xc4, 0x69, 0x20, 0xde,
-	0x9a, 0xbe, 0xa8, 0x71, 0xe7, 0x45, 0x66, 0x05, 0xf8, 0x6d, 0x76, 0xc1, 0xa2, 0x9f, 0x59, 0xf3,
-	0xf1, 0x74, 0x52, 0x5b, 0x23, 0x45, 0x09, 0x32, 0xab, 0x88, 0x7b, 0x36, 0x19, 0x73, 0xc7, 0xfa,
-	0x3d, 0xef, 0x98, 0x49, 0xc4, 0x5c, 0x32, 0xa7, 0x59, 0xff, 0xc3, 0x41, 0xae, 0x5e, 0x23, 0x47,
-	0xa1, 0x90, 0xf8, 0xfb, 0x5b, 0xab, 0xc4, 0x5f, 0xac, 0x74, 0x8a, 0xad, 0x17, 0xc9, 0xa6, 0xe9,
-	0xca, 0x4a, 0x66, 0x29, 0xac, 0x91, 0x33, 0x54, 0x0e, 0x25, 0x8c, 0x84, 0xf7, 0x60, 0xbb, 0xd4,
-	0x58, 0xdd, 0x0f, 0x16, 0x6f, 0x01, 0x1d, 0x61, 0x73, 0x2d, 0x1b, 0xce, 0x96, 0x52, 0x21, 0xa9,
-	0x58, 0xbd, 0x83, 0xd6, 0x3f, 0xe7, 0x51, 0x12, 0x13, 0x48, 0x1b, 0x4e, 0xe0, 0x77, 0x50, 0xb9,
-	0xaf, 0x2c, 0x3a, 0x05, 0xd7, 0xd2, 0x52, 0x58, 0xea, 0x53, 0x0d, 0xcc, 0x33, 0x86, 0x0e, 0xc8,
-	0x34, 0x70, 0x2e, 0x43, 0xac, 0xbf, 0xfe, 0x6b, 0x09, 0x6d, 0xcc, 0xb5, 0x21, 0xde, 0x41, 0x95,
-	0x0c, 0x60, 0x2e, 0xca, 0x73, 0xcf, 0x34, 0x48, 0x8e, 0xc0, 0x01, 0x72, 0x19, 0x1d, 0x81, 0x88,
-	0x69, 0x17, 0xcc, 0x1a, 0xcd, 0x17, 0xdd, 0x71, 0xe6, 0x20, 0x16, 0xa3, 0xd6, 0x86, 0x3a, 0xe8,
-	0x05, 0x5a, 0x58, 0x1b, 0x0a, 0x4b, 0xb4, 0x07, 0x37, 0x51, 0x29, 0x09, 0x7b, 0x66, 0x0d, 0xee,
-	0x1a, 0x40, 0xa9, 0xbd, 0xe8, 0x0a, 0x54, 0x64, 0xb5, 0xd0, 0x68, 0x1c, 0x3e, 0x07, 0x2e, 0xc2,
-	0x88, 0x99, 0x1d, 0x98, 0x2f, 0xb4, 0xc3, 0x93, 0x96, 0xf1, 0x90, 0x02, 0x0a, 0x1f, 0xa2, 0x8d,
-	0x2c, 0xad, 0x8c, 0x98, 0x6e, 0xc2, 0xb7, 0x0c, 0x71, 0x83, 0xcc, 0xba, 0xc9, 0x3c, 0x1e, 0x7f,
-	0x84, 0x56, 0x45, 0xd2, 0xc9, 0xcb, 0x97, 0xae, 0xc6, 0x27, 0x86, 0xbe, 0x7a, 0x6a, 0x5d, 0xa4,
-	0x88, 0xab, 0xff, 0xed, 0xa0, 0x87, 0x27, 0xd1, 0x30, 0xec, 0x5e, 0xbe, 0x86, 0x47, 0xef, 0x1b,
-	0x54, 0xe6, 0xc9, 0x10, 0xb2, 0x6e, 0x3d, 0x58, 0xbc, 0x5b, 0xd3, 0x10, 0x49, 0x32, 0x04, 0xdb,
-	0x7b, 0xea, 0x24, 0x48, 0xaa, 0x58, 0xff, 0xd3, 0x41, 0x28, 0x05, 0xbd, 0x86, 0xa9, 0x6b, 0xcf,
-	0x4e, 0xdd, 0xee, 0x7d, 0xf3, 0xb8, 0x63, 0xec, 0x7e, 0x2b, 0x65, 0x39, 0xa8, 0xd4, 0xec, 0x5f,
-	0x04, 0x67, 0x91, 0xbf, 0x08, 0x35, 0x54, 0x56, 0xef, 0x55, 0x36, 0x78, 0xae, 0x42, 0xaa, 0x67,
-	0x45, 0x90, 0xd4, 0x8e, 0x7d, 0x84, 0xd4, 0x87, 0x9e, 0x58, 0xe1, 0x95, 0x34, 0x6a, 0x5d, 0xfd,
-	0x54, 0xed, 0xdc, 0x4a, 0x0a, 0x08, 0x25, 0xa8, 0x9e, 0x52, 0xe1, 0x2d, 0x5b, 0x41, 0xf5, 0xc2,
-	0x0a, 0x92, 0xda, 0x71, 0x58, 0x1c, 0xf7, 0xb2, 0xae, 0xc4, 0xd3, 0xc5, 0x2b, 0x31, 0xbb, 0x60,
-	0xec, 0xe4, 0xbe, 0x6a, 0x59, 0xa8, 0xd8, 0xf3, 0x31, 0x16, 0xde, 0x43, 0x1b, 0x7b, 0x3e, 0xe7,
-	0x82, 0x14, 0x10, 0xf8, 0x53, 0xb4, 0xc1, 0x22, 0x96, 0x49, 0xb5, 0xc9, 0x91, 0xf0, 0x56, 0x34,
-	0xe9, 0x89, 0x9a, 0xa5, 0xe3, 0x59, 0x17, 0x99, 0xc7, 0x36, 0xfd, 0xab, 0xeb, 0xea, 0xd2, 0x8b,
-	0xeb, 0xea, 0xd2, 0xcb, 0xeb, 0xea, 0xd2, 0x2f, 0xd3, 0xaa, 0x73, 0x35, 0xad, 0x3a, 0x2f, 0xa6,
-	0x55, 0xe7, 0xe5, 0xb4, 0xea, 0xfc, 0x33, 0xad, 0x3a, 0xbf, 0xff, 0x5b, 0x5d, 0xfa, 0xb6, 0x92,
-	0xe5, 0xf2, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcf, 0xdb, 0xd3, 0xc6, 0xe7, 0x0b, 0x00, 0x00,
+	// 1107 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcf, 0x6f, 0xe3, 0x44,
+	0x14, 0xae, 0x37, 0x4d, 0x1b, 0x4f, 0xb7, 0x3f, 0x76, 0x16, 0x81, 0xd5, 0x43, 0x52, 0x82, 0x84,
+	0x22, 0x28, 0x76, 0x5b, 0x0a, 0x2c, 0x07, 0x0e, 0x8d, 0x16, 0x41, 0xa4, 0x52, 0xca, 0xb4, 0x59,
+	0x89, 0x1f, 0x07, 0x9c, 0xe4, 0x35, 0x31, 0x4d, 0x6c, 0x33, 0x33, 0x0e, 0xea, 0x8d, 0x03, 0xe2,
+	0xcc, 0x9d, 0x3f, 0x06, 0x21, 0x81, 0xd4, 0xe3, 0x1e, 0xf7, 0x14, 0xd1, 0xf0, 0x5f, 0xf4, 0x84,
+	0x66, 0x3c, 0xe3, 0xb1, 0xd3, 0x8d, 0x48, 0x2f, 0x7b, 0xf3, 0xbc, 0xf7, 0x7d, 0xdf, 0xbc, 0xf7,
+	0xfc, 0xde, 0xb3, 0xd1, 0x57, 0x97, 0x4f, 0x98, 0x1b, 0x44, 0xde, 0x65, 0xd2, 0x01, 0x1a, 0x02,
+	0x07, 0xe6, 0x8d, 0x21, 0xec, 0x45, 0xd4, 0x53, 0x0e, 0x3f, 0x0e, 0x18, 0xd0, 0x31, 0x50, 0x2f,
+	0xbe, 0xec, 0xcb, 0x93, 0xe7, 0x27, 0xbd, 0x80, 0x7b, 0xe3, 0x7d, 0x7f, 0x18, 0x0f, 0xfc, 0x7d,
+	0xaf, 0x0f, 0x21, 0x50, 0x9f, 0x43, 0xcf, 0x8d, 0x69, 0xc4, 0x23, 0xdc, 0x48, 0x99, 0x6e, 0xc6,
+	0x74, 0xe3, 0xcb, 0xbe, 0x3c, 0xb9, 0x92, 0xe9, 0x6a, 0xe6, 0xf6, 0x7b, 0xfd, 0x80, 0x0f, 0x92,
+	0x8e, 0xdb, 0x8d, 0x46, 0x5e, 0x3f, 0xea, 0x47, 0x9e, 0x14, 0xe8, 0x24, 0x17, 0xf2, 0x24, 0x0f,
+	0xf2, 0x29, 0x15, 0xde, 0xde, 0x35, 0x21, 0x79, 0x7e, 0xc2, 0x07, 0x10, 0xf2, 0xa0, 0xeb, 0xf3,
+	0x20, 0x0a, 0xbd, 0xf1, 0x9d, 0x30, 0xb6, 0x0f, 0x0d, 0x7a, 0xe4, 0x77, 0x07, 0x41, 0x08, 0xf4,
+	0xca, 0xe4, 0x30, 0x02, 0xee, 0xbf, 0x8c, 0xe5, 0xcd, 0x63, 0xd1, 0x24, 0xe4, 0xc1, 0x08, 0xee,
+	0x10, 0x3e, 0xfc, 0x3f, 0x02, 0xeb, 0x0e, 0x60, 0xe4, 0xdf, 0xe1, 0xbd, 0x3f, 0x8f, 0x97, 0xf0,
+	0x60, 0xe8, 0x05, 0x21, 0x67, 0x9c, 0xce, 0x92, 0xea, 0x7f, 0x55, 0x50, 0xf9, 0xd3, 0x31, 0x84,
+	0x1c, 0x7f, 0x8f, 0x2a, 0x22, 0x85, 0x9e, 0xcf, 0x7d, 0xc7, 0xda, 0xb1, 0x1a, 0x6b, 0x07, 0x7b,
+	0xae, 0xa9, 0x7b, 0xa6, 0x68, 0x4a, 0x2f, 0xd0, 0xee, 0x78, 0xdf, 0xfd, 0xb2, 0xf3, 0x03, 0x74,
+	0xf9, 0x17, 0xc0, 0xfd, 0x26, 0xbe, 0x9e, 0xd4, 0x96, 0xa6, 0x93, 0x1a, 0x32, 0x36, 0x92, 0xa9,
+	0xe2, 0x5d, 0x54, 0x1e, 0xc2, 0x18, 0x86, 0xce, 0x83, 0x1d, 0xab, 0x61, 0x37, 0x5f, 0x57, 0xe0,
+	0xf2, 0xb1, 0x30, 0xde, 0xea, 0x07, 0x92, 0x82, 0xf0, 0xb7, 0xc8, 0x16, 0xd9, 0x32, 0xee, 0x8f,
+	0x62, 0xa7, 0x24, 0x03, 0x7a, 0x67, 0xb1, 0x80, 0xce, 0x83, 0x11, 0x34, 0x1f, 0x29, 0x75, 0xfb,
+	0x5c, 0x8b, 0x10, 0xa3, 0x87, 0x4f, 0xd0, 0xaa, 0xec, 0x9c, 0xd6, 0x53, 0x67, 0x59, 0x06, 0x73,
+	0xa8, 0xe0, 0xab, 0x47, 0xa9, 0xf9, 0x76, 0x52, 0x7b, 0x73, 0x5e, 0x3d, 0xf9, 0x55, 0x0c, 0xcc,
+	0x6d, 0xb7, 0x9e, 0x12, 0x2d, 0x22, 0x52, 0x63, 0xdc, 0xef, 0x83, 0x53, 0x2e, 0xa6, 0x76, 0x26,
+	0x8c, 0xb7, 0xfa, 0x81, 0xa4, 0x20, 0x7c, 0x80, 0x10, 0x85, 0x1f, 0x13, 0x60, 0xbc, 0x4d, 0x5a,
+	0xce, 0x8a, 0xa4, 0x64, 0xa5, 0x23, 0x99, 0x87, 0xe4, 0x50, 0x78, 0x07, 0x2d, 0x8f, 0x81, 0x76,
+	0x9c, 0x55, 0x89, 0x7e, 0xa8, 0xd0, 0xcb, 0xcf, 0x80, 0x76, 0x88, 0xf4, 0xe0, 0xcf, 0xd1, 0x72,
+	0xc2, 0x80, 0x3a, 0x15, 0x59, 0xab, 0xb7, 0x73, 0xb5, 0x72, 0x8b, 0xbd, 0x2d, 0x6a, 0xd4, 0x66,
+	0x40, 0x5b, 0xe1, 0x45, 0x64, 0x94, 0x84, 0x85, 0x48, 0x05, 0x3c, 0x40, 0x5b, 0xc1, 0x28, 0x06,
+	0xca, 0xa2, 0x50, 0xb4, 0x8a, 0xf0, 0x38, 0xf6, 0xbd, 0x54, 0x5f, 0x9b, 0x4e, 0x6a, 0x5b, 0xad,
+	0x19, 0x0d, 0x72, 0x47, 0x15, 0xbf, 0x8b, 0x6c, 0x16, 0x25, 0xb4, 0x0b, 0xad, 0x53, 0xe6, 0xa0,
+	0x9d, 0x52, 0xc3, 0x6e, 0xae, 0x8b, 0x97, 0x76, 0xa6, 0x8d, 0xc4, 0xf8, 0xf1, 0x05, 0xb2, 0x23,
+	0xd9, 0x57, 0x04, 0x2e, 0x9c, 0x35, 0x19, 0xcf, 0xc7, 0xee, 0xa2, 0xab, 0x41, 0xb5, 0x29, 0x81,
+	0x0b, 0xa0, 0x10, 0x76, 0x21, 0xbd, 0x27, 0x33, 0x12, 0x23, 0x8d, 0x07, 0x68, 0x83, 0x02, 0x8b,
+	0xa3, 0x90, 0xc1, 0x19, 0xf7, 0x79, 0xc2, 0x9c, 0x87, 0xf2, 0xb2, 0xdd, 0xc5, 0xda, 0x2f, 0xe5,
+	0x34, 0xf1, 0x74, 0x52, 0xdb, 0x20, 0x05, 0x1d, 0x32, 0xa3, 0x8b, 0x7d, 0xb4, 0xae, 0x5e, 0x71,
+	0x1a, 0x88, 0xb3, 0x2e, 0x2f, 0x6a, 0xcc, 0xbd, 0x48, 0xad, 0x00, 0xb7, 0x1d, 0x5e, 0x86, 0xd1,
+	0x4f, 0x61, 0xf3, 0xd1, 0x74, 0x52, 0x5b, 0x27, 0x79, 0x09, 0x52, 0x54, 0xc4, 0x3d, 0x93, 0x8c,
+	0xba, 0x63, 0xe3, 0x9e, 0x77, 0x14, 0x12, 0x51, 0x97, 0xcc, 0x68, 0xd6, 0xff, 0xb0, 0x90, 0x2d,
+	0xd7, 0xc8, 0x71, 0xc0, 0x38, 0xfe, 0xee, 0xce, 0x2a, 0x71, 0x17, 0x2b, 0x9d, 0x60, 0xcb, 0x45,
+	0xb2, 0xa5, 0xba, 0xb2, 0xa2, 0x2d, 0xb9, 0x35, 0x72, 0x8e, 0xca, 0x01, 0x87, 0x11, 0x73, 0x1e,
+	0xec, 0x94, 0x1a, 0x6b, 0x07, 0xde, 0xe2, 0x2d, 0x20, 0x23, 0x6c, 0xae, 0xeb, 0xe1, 0x6c, 0x09,
+	0x15, 0x92, 0x8a, 0xd5, 0x7f, 0xb7, 0xd0, 0xc6, 0x67, 0x34, 0x4a, 0x62, 0x02, 0x69, 0xc7, 0x31,
+	0xfc, 0x16, 0x2a, 0xf7, 0x85, 0x45, 0xe6, 0x60, 0x1b, 0x5e, 0x0a, 0x4b, 0x7d, 0xa2, 0x83, 0xa9,
+	0x66, 0xc8, 0x88, 0x54, 0x07, 0x67, 0x32, 0xc4, 0xf8, 0xf1, 0x47, 0xe2, 0x7d, 0xa7, 0x87, 0x13,
+	0x7f, 0x04, 0xcc, 0x29, 0x49, 0x82, 0x7a, 0x8b, 0x39, 0x07, 0x29, 0xe2, 0xea, 0xbf, 0x94, 0xd0,
+	0xe6, 0x4c, 0x03, 0xe3, 0x5d, 0x54, 0xd1, 0x20, 0x15, 0x61, 0x56, 0x35, 0xad, 0x45, 0x32, 0x04,
+	0xf6, 0x90, 0x1d, 0x0a, 0xa9, 0xd8, 0xef, 0x82, 0x5a, 0xc0, 0xd9, 0x8a, 0x3c, 0xd1, 0x0e, 0x62,
+	0x30, 0x62, 0xe1, 0x88, 0x83, 0x5c, 0xbd, 0xb9, 0x85, 0x23, 0xb0, 0x44, 0x7a, 0x70, 0x13, 0x95,
+	0x92, 0xa0, 0xa7, 0x16, 0xe8, 0x9e, 0x02, 0x94, 0xda, 0x8b, 0x2e, 0x4f, 0x41, 0x16, 0xab, 0xd0,
+	0x8f, 0x83, 0x67, 0x40, 0x59, 0x10, 0x85, 0x6a, 0x7b, 0x66, 0xab, 0xf0, 0xe8, 0xb4, 0xa5, 0x3c,
+	0x24, 0x87, 0xc2, 0x47, 0x68, 0x53, 0xa7, 0xa5, 0x89, 0xe9, 0x0e, 0x7d, 0x43, 0x11, 0x37, 0x49,
+	0xd1, 0x4d, 0x66, 0xf1, 0xf8, 0x03, 0xb4, 0xc6, 0x92, 0x4e, 0x56, 0xbe, 0x74, 0xa9, 0x3e, 0x56,
+	0xf4, 0xb5, 0x33, 0xe3, 0x22, 0x79, 0x5c, 0xfd, 0x6f, 0x0b, 0xad, 0x9c, 0x46, 0xc3, 0xa0, 0x7b,
+	0xf5, 0x0a, 0x3e, 0x97, 0x5f, 0xa3, 0x32, 0x4d, 0x86, 0xa0, 0xfb, 0xfc, 0x70, 0xf1, 0x3e, 0x4f,
+	0x43, 0x24, 0xc9, 0x10, 0x4c, 0xd3, 0x8a, 0x13, 0x23, 0xa9, 0x62, 0xfd, 0x4f, 0x0b, 0xa1, 0x14,
+	0xf4, 0x0a, 0xe6, 0xb5, 0x5d, 0x9c, 0xd7, 0xbd, 0xfb, 0xe6, 0x31, 0x67, 0x60, 0x7f, 0x2d, 0xe9,
+	0x1c, 0x44, 0x6a, 0xe6, 0xe7, 0xc2, 0x5a, 0xe4, 0xe7, 0xa2, 0x86, 0xca, 0xe2, 0x4b, 0xa7, 0x27,
+	0xd6, 0x16, 0x48, 0xf1, 0x41, 0x62, 0x24, 0xb5, 0x63, 0x17, 0x21, 0xf1, 0x20, 0x47, 0x5d, 0x8f,
+	0xe9, 0x86, 0x78, 0x55, 0xed, 0xcc, 0x4a, 0x72, 0x08, 0x21, 0x28, 0x3e, 0xc2, 0xcc, 0x59, 0x36,
+	0x82, 0xe2, 0xdb, 0xcc, 0x48, 0x6a, 0xc7, 0x41, 0x7e, 0x4f, 0x94, 0x65, 0x25, 0x9e, 0x2c, 0x5e,
+	0x89, 0xe2, 0x66, 0x32, 0x93, 0xfb, 0xd2, 0x2d, 0xe3, 0x22, 0x94, 0x8d, 0x31, 0x73, 0x56, 0x4c,
+	0xec, 0xd9, 0x9c, 0x33, 0x92, 0x43, 0xe0, 0x4f, 0xd0, 0x66, 0x18, 0x85, 0x5a, 0xaa, 0x4d, 0x8e,
+	0x99, 0xb3, 0x2a, 0x49, 0x8f, 0xc5, 0x2c, 0x9d, 0x14, 0x5d, 0x64, 0x16, 0xdb, 0x74, 0xaf, 0x6f,
+	0xaa, 0x4b, 0xcf, 0x6f, 0xaa, 0x4b, 0x2f, 0x6e, 0xaa, 0x4b, 0x3f, 0x4f, 0xab, 0xd6, 0xf5, 0xb4,
+	0x6a, 0x3d, 0x9f, 0x56, 0xad, 0x17, 0xd3, 0xaa, 0xf5, 0xcf, 0xb4, 0x6a, 0xfd, 0xf6, 0x6f, 0x75,
+	0xe9, 0x9b, 0x8a, 0xce, 0xe5, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6c, 0x88, 0x4f, 0x33, 0x21,
+	0x0c, 0x00, 0x00,
 }
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto
index e60acf88b48..9cf0627b1a8 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto
@@ -106,10 +106,18 @@ message GroupResources {
   // +optional
   optional string group = 1;
 
-  // Resources is a list of resources within the API group.
-  // Any empty list implies every resource kind in the API group.
+  // Resources is a list of resources within the API group. Subresources are
+  // matched using a "/" to indicate the subresource. For example, "pods/logs"
+  // would match request to the logs subresource of pods. The top level resource
+  // does not match subresources, "pods" doesn't match "pods/logs".
   // +optional
   repeated string resources = 2;
+
+  // ResourceNames is a list of resource instance names that the policy matches.
+  // Using this field requires Resources to be specified.
+  // An empty list implies that every instance of the resource is matched.
+  // +optional
+  repeated string resourceNames = 3;
 }
 
 // ObjectReference contains enough information to let you inspect or modify the referred object.
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.generated.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.generated.go
index d85163dd7e1..42127762639 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.generated.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.generated.go
@@ -2887,14 +2887,15 @@ func (x *GroupResources) CodecEncodeSelf(e *codec1978.Encoder) {
 		} else {
 			yysep2 := !z.EncBinary()
 			yy2arr2 := z.EncBasicHandle().StructToArray
-			var yyq2 [2]bool
+			var yyq2 [3]bool
 			_, _, _ = yysep2, yyq2, yy2arr2
 			const yyr2 bool = false
 			yyq2[0] = x.Group != ""
 			yyq2[1] = len(x.Resources) != 0
+			yyq2[2] = len(x.ResourceNames) != 0
 			var yynn2 int
 			if yyr2 || yy2arr2 {
-				r.EncodeArrayStart(2)
+				r.EncodeArrayStart(3)
 			} else {
 				yynn2 = 0
 				for _, b := range yyq2 {
@@ -2963,6 +2964,39 @@ func (x *GroupResources) CodecEncodeSelf(e *codec1978.Encoder) {
 					}
 				}
 			}
+			if yyr2 || yy2arr2 {
+				z.EncSendContainerState(codecSelfer_containerArrayElem1234)
+				if yyq2[2] {
+					if x.ResourceNames == nil {
+						r.EncodeNil()
+					} else {
+						yym10 := z.EncBinary()
+						_ = yym10
+						if false {
+						} else {
+							z.F.EncSliceStringV(x.ResourceNames, false, e)
+						}
+					}
+				} else {
+					r.EncodeNil()
+				}
+			} else {
+				if yyq2[2] {
+					z.EncSendContainerState(codecSelfer_containerMapKey1234)
+					r.EncodeString(codecSelferC_UTF81234, string("resourceNames"))
+					z.EncSendContainerState(codecSelfer_containerMapValue1234)
+					if x.ResourceNames == nil {
+						r.EncodeNil()
+					} else {
+						yym11 := z.EncBinary()
+						_ = yym11
+						if false {
+						} else {
+							z.F.EncSliceStringV(x.ResourceNames, false, e)
+						}
+					}
+				}
+			}
 			if yyr2 || yy2arr2 {
 				z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
 			} else {
@@ -3048,6 +3082,18 @@ func (x *GroupResources) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
 					z.F.DecSliceStringX(yyv6, false, d)
 				}
 			}
+		case "resourceNames":
+			if r.TryDecodeAsNil() {
+				x.ResourceNames = nil
+			} else {
+				yyv8 := &x.ResourceNames
+				yym9 := z.DecBinary()
+				_ = yym9
+				if false {
+				} else {
+					z.F.DecSliceStringX(yyv8, false, d)
+				}
+			}
 		default:
 			z.DecStructFieldNotFound(-1, yys3)
 		} // end switch yys3
@@ -3059,16 +3105,16 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
 	var h codecSelfer1234
 	z, r := codec1978.GenHelperDecoder(d)
 	_, _, _ = h, z, r
-	var yyj8 int
-	var yyb8 bool
-	var yyhl8 bool = l >= 0
-	yyj8++
-	if yyhl8 {
-		yyb8 = yyj8 > l
+	var yyj10 int
+	var yyb10 bool
+	var yyhl10 bool = l >= 0
+	yyj10++
+	if yyhl10 {
+		yyb10 = yyj10 > l
 	} else {
-		yyb8 = r.CheckBreak()
+		yyb10 = r.CheckBreak()
 	}
-	if yyb8 {
+	if yyb10 {
 		z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
 		return
 	}
@@ -3076,21 +3122,21 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
 	if r.TryDecodeAsNil() {
 		x.Group = ""
 	} else {
-		yyv9 := &x.Group
-		yym10 := z.DecBinary()
-		_ = yym10
+		yyv11 := &x.Group
+		yym12 := z.DecBinary()
+		_ = yym12
 		if false {
 		} else {
-			*((*string)(yyv9)) = r.DecodeString()
+			*((*string)(yyv11)) = r.DecodeString()
 		}
 	}
-	yyj8++
-	if yyhl8 {
-		yyb8 = yyj8 > l
+	yyj10++
+	if yyhl10 {
+		yyb10 = yyj10 > l
 	} else {
-		yyb8 = r.CheckBreak()
+		yyb10 = r.CheckBreak()
 	}
-	if yyb8 {
+	if yyb10 {
 		z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
 		return
 	}
@@ -3098,26 +3144,48 @@ func (x *GroupResources) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
 	if r.TryDecodeAsNil() {
 		x.Resources = nil
 	} else {
-		yyv11 := &x.Resources
-		yym12 := z.DecBinary()
-		_ = yym12
+		yyv13 := &x.Resources
+		yym14 := z.DecBinary()
+		_ = yym14
 		if false {
 		} else {
-			z.F.DecSliceStringX(yyv11, false, d)
+			z.F.DecSliceStringX(yyv13, false, d)
+		}
+	}
+	yyj10++
+	if yyhl10 {
+		yyb10 = yyj10 > l
+	} else {
+		yyb10 = r.CheckBreak()
+	}
+	if yyb10 {
+		z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
+		return
+	}
+	z.DecSendContainerState(codecSelfer_containerArrayElem1234)
+	if r.TryDecodeAsNil() {
+		x.ResourceNames = nil
+	} else {
+		yyv15 := &x.ResourceNames
+		yym16 := z.DecBinary()
+		_ = yym16
+		if false {
+		} else {
+			z.F.DecSliceStringX(yyv15, false, d)
 		}
 	}
 	for {
-		yyj8++
-		if yyhl8 {
-			yyb8 = yyj8 > l
+		yyj10++
+		if yyhl10 {
+			yyb10 = yyj10 > l
 		} else {
-			yyb8 = r.CheckBreak()
+			yyb10 = r.CheckBreak()
 		}
-		if yyb8 {
+		if yyb10 {
 			break
 		}
 		z.DecSendContainerState(codecSelfer_containerArrayElem1234)
-		z.DecStructFieldNotFound(yyj8-1, "")
+		z.DecStructFieldNotFound(yyj10-1, "")
 	}
 	z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
 }
@@ -4063,7 +4131,7 @@ func (x codecSelfer1234) decSliceGroupResources(v *[]GroupResources, d *codec197
 
 			yyrg1 := len(yyv1) > 0
 			yyv21 := yyv1
-			yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40)
+			yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 64)
 			if yyrt1 {
 				if yyrl1 <= cap(yyv1) {
 					yyv1 = yyv1[:yyrl1]
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.go
index e2022656828..9eaaa111136 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/types.go
@@ -216,10 +216,17 @@ type GroupResources struct {
 	// The empty string represents the core API group.
 	// +optional
 	Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"`
-	// Resources is a list of resources within the API group.
-	// Any empty list implies every resource kind in the API group.
+	// Resources is a list of resources within the API group. Subresources are
+	// matched using a "/" to indicate the subresource. For example, "pods/logs"
+	// would match request to the logs subresource of pods. The top level resource
+	// does not match subresources, "pods" doesn't match "pods/logs".
 	// +optional
 	Resources []string `json:"resources,omitempty" protobuf:"bytes,2,rep,name=resources"`
+	// ResourceNames is a list of resource instance names that the policy matches.
+	// Using this field requires Resources to be specified.
+	// An empty list implies that every instance of the resource is matched.
+	// +optional
+	ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,3,rep,name=resourceNames"`
 }
 
 // ObjectReference contains enough information to let you inspect or modify the referred object.
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go
index 8007dda36e8..ddd12c1dfcd 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go
@@ -132,6 +132,7 @@ func Convert_audit_EventList_To_v1alpha1_EventList(in *audit.EventList, out *Eve
 func autoConvert_v1alpha1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error {
 	out.Group = in.Group
 	out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
+	out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
 	return nil
 }
 
@@ -143,6 +144,7 @@ func Convert_v1alpha1_GroupResources_To_audit_GroupResources(in *GroupResources,
 func autoConvert_audit_GroupResources_To_v1alpha1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error {
 	out.Group = in.Group
 	out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
+	out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
 	return nil
 }
 
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go
index 7afe30d3e81..19a737bf75f 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go
@@ -190,6 +190,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
+	if in.ResourceNames != nil {
+		in, out := &in.ResourceNames, &out.ResourceNames
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
 	return
 }
 
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go
index 1ecac858854..b60b78ec49f 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/types.go
@@ -209,10 +209,17 @@ type GroupResources struct {
 	// The empty string represents the core API group.
 	// +optional
 	Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"`
-	// Resources is a list of resources within the API group.
-	// Any empty list implies every resource kind in the API group.
+	// Resources is a list of resources within the API group. Subresources are
+	// matched using a "/" to indicate the subresource. For example, "pods/logs"
+	// would match request to the logs subresource of pods. The top level resource
+	// does not match subresources, "pods" doesn't match "pods/logs".
 	// +optional
 	Resources []string `json:"resources,omitempty" protobuf:"bytes,2,rep,name=resources"`
+	// ResourceNames is a list of resource instance names that the policy matches.
+	// Using this field requires Resources to be specified.
+	// An empty list implies that every instance of the resource is matched.
+	// +optional
+	ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,3,rep,name=resourceNames"`
 }
 
 // ObjectReference contains enough information to let you inspect or modify the referred object.
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go
index 905420af9de..98ebeaf53d9 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go
@@ -132,6 +132,7 @@ func Convert_audit_EventList_To_v1beta1_EventList(in *audit.EventList, out *Even
 func autoConvert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources, out *audit.GroupResources, s conversion.Scope) error {
 	out.Group = in.Group
 	out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
+	out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
 	return nil
 }
 
@@ -143,6 +144,7 @@ func Convert_v1beta1_GroupResources_To_audit_GroupResources(in *GroupResources,
 func autoConvert_audit_GroupResources_To_v1beta1_GroupResources(in *audit.GroupResources, out *GroupResources, s conversion.Scope) error {
 	out.Group = in.Group
 	out.Resources = *(*[]string)(unsafe.Pointer(&in.Resources))
+	out.ResourceNames = *(*[]string)(unsafe.Pointer(&in.ResourceNames))
 	return nil
 }
 
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go
index 28c841d3b87..e799a0f58c4 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go
@@ -190,6 +190,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
+	if in.ResourceNames != nil {
+		in, out := &in.ResourceNames, &out.ResourceNames
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
 	return
 }
 
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation.go
index 80b73f851cb..0db2030433a 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation.go
@@ -88,16 +88,18 @@ func validateResources(groupResources []audit.GroupResources, fldPath *field.Pat
 	var allErrs field.ErrorList
 	for _, groupResource := range groupResources {
 		// The empty string represents the core API group.
-		if len(groupResource.Group) == 0 {
-			continue
+		if len(groupResource.Group) != 0 {
+			// Group names must be lower case and be valid DNS subdomains.
+			// reference: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md
+			// an error is returned for group name like rbac.authorization.k8s.io/v1beta1
+			// rbac.authorization.k8s.io is the valid one
+			if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 {
+				allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), groupResource.Group, strings.Join(msgs, ",")))
+			}
 		}
 
-		// Group names must be lower case and be valid DNS subdomains.
-		// reference: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md
-		// an error is returned for group name like rbac.authorization.k8s.io/v1beta1
-		// rbac.authorization.k8s.io is the valid one
-		if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 {
-			allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), groupResource.Group, strings.Join(msgs, ",")))
+		if len(groupResource.ResourceNames) > 0 && len(groupResource.Resources) == 0 {
+			allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceNames"), groupResource.ResourceNames, "using resourceNames requires at least one resource"))
 		}
 	}
 	return allErrs
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation_test.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation_test.go
index 99692157791..3acb9598bd0 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation_test.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/validation/validation_test.go
@@ -102,6 +102,12 @@ func TestValidatePolicy(t *testing.T) {
 				"/metrics",
 			},
 		},
+		{ // ResourceNames without Resources
+			Level:      audit.LevelMetadata,
+			Verbs:      []string{"get"},
+			Resources:  []audit.GroupResources{{ResourceNames: []string{"leader"}}},
+			Namespaces: []string{"kube-system"},
+		},
 	}
 	errorCases := []audit.Policy{}
 	for _, rule := range invalidRules {
diff --git a/staging/src/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go b/staging/src/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go
index 3f6766d81b4..73bd386d78b 100644
--- a/staging/src/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go
+++ b/staging/src/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go
@@ -188,6 +188,11 @@ func (in *GroupResources) DeepCopyInto(out *GroupResources) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
+	if in.ResourceNames != nil {
+		in, out := &in.ResourceNames, &out.ResourceNames
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
 	return
 }
 
diff --git a/staging/src/k8s.io/apiserver/pkg/audit/policy/checker.go b/staging/src/k8s.io/apiserver/pkg/audit/policy/checker.go
index 526710c2c6f..8ebe69ca136 100644
--- a/staging/src/k8s.io/apiserver/pkg/audit/policy/checker.go
+++ b/staging/src/k8s.io/apiserver/pkg/audit/policy/checker.go
@@ -143,6 +143,15 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool
 
 	apiGroup := attrs.GetAPIGroup()
 	resource := attrs.GetResource()
+	// If subresource, the resource in the policy must match "(resource)/(subresource)"
+	//
+	// TODO: consider adding options like "pods/*" to match all subresources.
+	if sr := attrs.GetSubresource(); sr != "" {
+		resource = resource + "/" + sr
+	}
+
+	name := attrs.GetName()
+
 	for _, gr := range r.Resources {
 		if gr.Group == apiGroup {
 			if len(gr.Resources) == 0 {
@@ -150,7 +159,9 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool
 			}
 			for _, res := range gr.Resources {
 				if res == resource {
-					return true
+					if len(gr.ResourceNames) == 0 || hasString(gr.ResourceNames, name) {
+						return true
+					}
 				}
 			}
 		}
diff --git a/staging/src/k8s.io/apiserver/pkg/audit/policy/checker_test.go b/staging/src/k8s.io/apiserver/pkg/audit/policy/checker_test.go
index 29cf1a4689a..015e23beb7e 100644
--- a/staging/src/k8s.io/apiserver/pkg/audit/policy/checker_test.go
+++ b/staging/src/k8s.io/apiserver/pkg/audit/policy/checker_test.go
@@ -61,6 +61,18 @@ func TestChecker(t *testing.T) {
 			ResourceRequest: false,
 			Path:            "/logs/kubelet.log",
 		},
+		"subresource": &authorizer.AttributesRecord{
+			User:            tim,
+			Verb:            "get",
+			Namespace:       "default",
+			APIGroup:        "", // Core
+			APIVersion:      "v1",
+			Resource:        "pods",
+			Subresource:     "log",
+			Name:            "busybox",
+			ResourceRequest: true,
+			Path:            "/api/v1/namespaces/default/pods/busybox",
+		},
 	}
 
 	rules := map[string]audit.PolicyRule{
@@ -88,6 +100,11 @@ func TestChecker(t *testing.T) {
 			Verbs:     []string{"get"},
 			Resources: []audit.GroupResources{{Resources: []string{"pods"}}},
 		},
+		"getPodLogs": {
+			Level:     audit.LevelRequest,
+			Verbs:     []string{"get"},
+			Resources: []audit.GroupResources{{Resources: []string{"pods/log"}}},
+		},
 		"getClusterRoles": {
 			Level: audit.LevelRequestResponse,
 			Verbs: []string{"get"},
@@ -111,6 +128,14 @@ func TestChecker(t *testing.T) {
 				"/metrics",
 			},
 		},
+		"clusterRoleEdit": {
+			Level: audit.LevelRequest,
+			Resources: []audit.GroupResources{{
+				Group:         "rbac.authorization.k8s.io",
+				Resources:     []string{"clusterroles"},
+				ResourceNames: []string{"edit"},
+			}},
+		},
 	}
 
 	test := func(req string, expected audit.Level, ruleNames ...string) {
@@ -135,6 +160,7 @@ func TestChecker(t *testing.T) {
 	test("namespaced", audit.LevelNone, "getMetrics")
 	test("namespaced", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default")
 	test("namespaced", audit.LevelRequestResponse, "getMetrics", "getPods", "default")
+	test("namespaced", audit.LevelRequestResponse, "getPodLogs", "getPods")
 
 	test("cluster", audit.LevelMetadata, "default")
 	test("cluster", audit.LevelNone, "create")
@@ -143,10 +169,12 @@ func TestChecker(t *testing.T) {
 	test("cluster", audit.LevelNone, "serviceAccounts")
 	test("cluster", audit.LevelNone, "getPods")
 	test("cluster", audit.LevelRequestResponse, "getClusterRoles")
+	test("cluster", audit.LevelRequest, "clusterRoleEdit", "getClusterRoles")
 	test("cluster", audit.LevelNone, "getLogs")
 	test("cluster", audit.LevelNone, "getMetrics")
 	test("cluster", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default")
 	test("cluster", audit.LevelRequestResponse, "getMetrics", "getClusterRoles", "default")
+	test("cluster", audit.LevelNone, "getPodLogs", "getPods")
 
 	test("nonResource", audit.LevelMetadata, "default")
 	test("nonResource", audit.LevelNone, "create")
@@ -159,4 +187,8 @@ func TestChecker(t *testing.T) {
 	test("nonResource", audit.LevelNone, "getMetrics")
 	test("nonResource", audit.LevelMetadata, "getMetrics", "serviceAccounts", "default")
 	test("nonResource", audit.LevelRequestResponse, "getLogs", "getClusterRoles", "default")
+	test("nonResource", audit.LevelNone, "getPodLogs", "getPods")
+
+	test("subresource", audit.LevelRequest, "getPodLogs", "getPods")
+	test("subresource", audit.LevelRequest, "getPods", "getPodLogs")
 }