From 379683d9f4fe52053311c1ba8cb4ba8bece0e754 Mon Sep 17 00:00:00 2001 From: Slava Semushin Date: Wed, 10 Jan 2018 17:52:26 +0100 Subject: [PATCH] Introduce PodSecurityPolicy in the policy/v1beta1 API group. PSP are completely the same as in extensions/v1beta1 except that they are located outside of the extensions API group. --- cmd/kube-apiserver/app/server.go | 3 + pkg/api/testing/defaulting_test.go | 2 + pkg/apis/policy/OWNERS | 4 + pkg/apis/policy/install/install.go | 2 + pkg/apis/policy/register.go | 3 + pkg/apis/policy/v1beta1/defaults.go | 35 +++ pkg/apis/policy/v1beta1/doc.go | 1 + .../default_storage_factory_builder.go | 1 + pkg/registry/policy/rest/storage_policy.go | 3 + staging/src/k8s.io/api/policy/OWNERS | 4 + .../src/k8s.io/api/policy/v1beta1/register.go | 2 + .../src/k8s.io/api/policy/v1beta1/types.go | 253 ++++++++++++++++++ .../etcd/etcd_storage_path_test.go | 5 + 13 files changed, 318 insertions(+) create mode 100644 pkg/apis/policy/v1beta1/defaults.go diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index be44798d9b7..2fc7245a489 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -69,6 +69,7 @@ import ( "k8s.io/kubernetes/pkg/apis/events" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/networking" + "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" @@ -600,6 +601,8 @@ func BuildStorageFactory(s *options.ServerRunOptions, apiResourceConfig *servers storageFactory.AddCohabitatingResources(apps.Resource("daemonsets"), extensions.Resource("daemonsets")) storageFactory.AddCohabitatingResources(apps.Resource("replicasets"), extensions.Resource("replicasets")) storageFactory.AddCohabitatingResources(api.Resource("events"), events.Resource("events")) + // TODO(#54933): 1.11: switch to using policy storage and flip the order here + storageFactory.AddCohabitatingResources(extensions.Resource("podsecuritypolicies"), policy.Resource("podsecuritypolicies")) for _, override := range s.Etcd.EtcdServersOverrides { tokens := strings.Split(override, "#") if len(tokens) != 2 { diff --git a/pkg/api/testing/defaulting_test.go b/pkg/api/testing/defaulting_test.go index 25ccdbaeca3..6c1c2af86f8 100644 --- a/pkg/api/testing/defaulting_test.go +++ b/pkg/api/testing/defaulting_test.go @@ -119,6 +119,8 @@ func TestDefaulting(t *testing.T) { {Group: "extensions", Version: "v1beta1", Kind: "ReplicaSetList"}: {}, {Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicy"}: {}, {Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicyList"}: {}, + {Group: "policy", Version: "v1beta1", Kind: "PodSecurityPolicy"}: {}, + {Group: "policy", Version: "v1beta1", Kind: "PodSecurityPolicyList"}: {}, {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBinding"}: {}, {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBindingList"}: {}, {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBinding"}: {}, diff --git a/pkg/apis/policy/OWNERS b/pkg/apis/policy/OWNERS index 99e0bffb533..a245fde358e 100755 --- a/pkg/apis/policy/OWNERS +++ b/pkg/apis/policy/OWNERS @@ -2,3 +2,7 @@ approvers: - sig-apps-api-approvers reviewers: - sig-apps-reviewers +- pweil- +- liggitt +- tallclair +- php-coder diff --git a/pkg/apis/policy/install/install.go b/pkg/apis/policy/install/install.go index 6c5703195b9..7a6db95728a 100644 --- a/pkg/apis/policy/install/install.go +++ b/pkg/apis/policy/install/install.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/apimachinery/announced" "k8s.io/apimachinery/pkg/apimachinery/registered" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/apis/policy/v1beta1" @@ -37,6 +38,7 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r &announced.GroupMetaFactoryArgs{ GroupName: policy.GroupName, VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version}, + RootScopedKinds: sets.NewString("PodSecurityPolicy"), AddInternalObjectsToScheme: policy.AddToScheme, }, announced.VersionToSchemeFunc{ diff --git a/pkg/apis/policy/register.go b/pkg/apis/policy/register.go index 80e834b385d..6a91919e096 100644 --- a/pkg/apis/policy/register.go +++ b/pkg/apis/policy/register.go @@ -19,6 +19,7 @@ package policy import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kubernetes/pkg/apis/extensions" ) // GroupName is the group name use in this package @@ -48,6 +49,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &PodDisruptionBudget{}, &PodDisruptionBudgetList{}, + &extensions.PodSecurityPolicy{}, + &extensions.PodSecurityPolicyList{}, &Eviction{}, ) return nil diff --git a/pkg/apis/policy/v1beta1/defaults.go b/pkg/apis/policy/v1beta1/defaults.go new file mode 100644 index 00000000000..47a3d1f9a58 --- /dev/null +++ b/pkg/apis/policy/v1beta1/defaults.go @@ -0,0 +1,35 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + policyv1beta1 "k8s.io/api/policy/v1beta1" + "k8s.io/apimachinery/pkg/runtime" +) + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func SetDefaults_PodSecurityPolicySpec(obj *policyv1beta1.PodSecurityPolicySpec) { + // This field was added after PodSecurityPolicy was released. + // Policies that do not include this field must remain as permissive as they were prior to the introduction of this field. + if obj.AllowPrivilegeEscalation == nil { + t := true + obj.AllowPrivilegeEscalation = &t + } +} diff --git a/pkg/apis/policy/v1beta1/doc.go b/pkg/apis/policy/v1beta1/doc.go index 9629da3fcd4..925a0b74235 100644 --- a/pkg/apis/policy/v1beta1/doc.go +++ b/pkg/apis/policy/v1beta1/doc.go @@ -15,6 +15,7 @@ limitations under the License. */ // +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/policy +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/extensions // +k8s:conversion-gen-external-types=k8s.io/api/policy/v1beta1 // +k8s:defaulter-gen=TypeMeta // +k8s:defaulter-gen-input=../../../../vendor/k8s.io/api/policy/v1beta1 diff --git a/pkg/kubeapiserver/default_storage_factory_builder.go b/pkg/kubeapiserver/default_storage_factory_builder.go index fa114e9412a..9b09d914128 100644 --- a/pkg/kubeapiserver/default_storage_factory_builder.go +++ b/pkg/kubeapiserver/default_storage_factory_builder.go @@ -33,6 +33,7 @@ var SpecialDefaultResourcePrefixes = map[schema.GroupResource]string{ {Group: "", Resource: "services"}: "services/specs", {Group: "extensions", Resource: "ingresses"}: "ingress", {Group: "extensions", Resource: "podsecuritypolicies"}: "podsecuritypolicy", + {Group: "policy", Resource: "podsecuritypolicies"}: "podsecuritypolicy", } // NewStorageFactory builds the DefaultStorageFactory. diff --git a/pkg/registry/policy/rest/storage_policy.go b/pkg/registry/policy/rest/storage_policy.go index 09a44d6a5af..153686d76a2 100644 --- a/pkg/registry/policy/rest/storage_policy.go +++ b/pkg/registry/policy/rest/storage_policy.go @@ -24,6 +24,7 @@ import ( serverstorage "k8s.io/apiserver/pkg/server/storage" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/policy" + pspstore "k8s.io/kubernetes/pkg/registry/extensions/podsecuritypolicy/storage" poddisruptionbudgetstore "k8s.io/kubernetes/pkg/registry/policy/poddisruptionbudget/storage" ) @@ -48,6 +49,8 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag storage["poddisruptionbudgets"] = poddisruptionbudgetStorage storage["poddisruptionbudgets/status"] = poddisruptionbudgetStatusStorage + storage["podsecuritypolicies"] = pspstore.NewREST(restOptionsGetter) + return storage } diff --git a/staging/src/k8s.io/api/policy/OWNERS b/staging/src/k8s.io/api/policy/OWNERS index 99e0bffb533..a245fde358e 100755 --- a/staging/src/k8s.io/api/policy/OWNERS +++ b/staging/src/k8s.io/api/policy/OWNERS @@ -2,3 +2,7 @@ approvers: - sig-apps-api-approvers reviewers: - sig-apps-reviewers +- pweil- +- liggitt +- tallclair +- php-coder diff --git a/staging/src/k8s.io/api/policy/v1beta1/register.go b/staging/src/k8s.io/api/policy/v1beta1/register.go index d77f1304070..b3efd6326b5 100644 --- a/staging/src/k8s.io/api/policy/v1beta1/register.go +++ b/staging/src/k8s.io/api/policy/v1beta1/register.go @@ -46,6 +46,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &PodDisruptionBudget{}, &PodDisruptionBudgetList{}, + &PodSecurityPolicy{}, + &PodSecurityPolicyList{}, &Eviction{}, ) // Add the watch version that applies diff --git a/staging/src/k8s.io/api/policy/v1beta1/types.go b/staging/src/k8s.io/api/policy/v1beta1/types.go index a69a5720756..6cea9615fff 100644 --- a/staging/src/k8s.io/api/policy/v1beta1/types.go +++ b/staging/src/k8s.io/api/policy/v1beta1/types.go @@ -17,6 +17,7 @@ limitations under the License. package v1beta1 import ( + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" ) @@ -113,3 +114,255 @@ type Eviction struct { // DeleteOptions may be provided DeleteOptions *metav1.DeleteOptions `json:"deleteOptions,omitempty" protobuf:"bytes,2,opt,name=deleteOptions"` } + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Pod Security Policy governs the ability to make requests that affect the Security Context +// that will be applied to a pod and container. +type PodSecurityPolicy struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // spec defines the policy enforced. + // +optional + Spec PodSecurityPolicySpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` +} + +// Pod Security Policy Spec defines the policy enforced. +type PodSecurityPolicySpec struct { + // privileged determines if a pod can request to be run as privileged. + // +optional + Privileged bool `json:"privileged,omitempty" protobuf:"varint,1,opt,name=privileged"` + // DefaultAddCapabilities is the default set of capabilities that will be added to the container + // unless the pod spec specifically drops the capability. You may not list a capability in both + // DefaultAddCapabilities and RequiredDropCapabilities. Capabilities added here are implicitly + // allowed, and need not be included in the AllowedCapabilities list. + // +optional + DefaultAddCapabilities []v1.Capability `json:"defaultAddCapabilities,omitempty" protobuf:"bytes,2,rep,name=defaultAddCapabilities,casttype=k8s.io/api/core/v1.Capability"` + // RequiredDropCapabilities are the capabilities that will be dropped from the container. These + // are required to be dropped and cannot be added. + // +optional + RequiredDropCapabilities []v1.Capability `json:"requiredDropCapabilities,omitempty" protobuf:"bytes,3,rep,name=requiredDropCapabilities,casttype=k8s.io/api/core/v1.Capability"` + // AllowedCapabilities is a list of capabilities that can be requested to add to the container. + // Capabilities in this field may be added at the pod author's discretion. + // You must not list a capability in both AllowedCapabilities and RequiredDropCapabilities. + // +optional + AllowedCapabilities []v1.Capability `json:"allowedCapabilities,omitempty" protobuf:"bytes,4,rep,name=allowedCapabilities,casttype=k8s.io/api/core/v1.Capability"` + // volumes is a white list of allowed volume plugins. Empty indicates that all plugins + // may be used. + // +optional + Volumes []FSType `json:"volumes,omitempty" protobuf:"bytes,5,rep,name=volumes,casttype=FSType"` + // hostNetwork determines if the policy allows the use of HostNetwork in the pod spec. + // +optional + HostNetwork bool `json:"hostNetwork,omitempty" protobuf:"varint,6,opt,name=hostNetwork"` + // hostPorts determines which host port ranges are allowed to be exposed. + // +optional + HostPorts []HostPortRange `json:"hostPorts,omitempty" protobuf:"bytes,7,rep,name=hostPorts"` + // hostPID determines if the policy allows the use of HostPID in the pod spec. + // +optional + HostPID bool `json:"hostPID,omitempty" protobuf:"varint,8,opt,name=hostPID"` + // hostIPC determines if the policy allows the use of HostIPC in the pod spec. + // +optional + HostIPC bool `json:"hostIPC,omitempty" protobuf:"varint,9,opt,name=hostIPC"` + // seLinux is the strategy that will dictate the allowable labels that may be set. + SELinux SELinuxStrategyOptions `json:"seLinux" protobuf:"bytes,10,opt,name=seLinux"` + // runAsUser is the strategy that will dictate the allowable RunAsUser values that may be set. + RunAsUser RunAsUserStrategyOptions `json:"runAsUser" protobuf:"bytes,11,opt,name=runAsUser"` + // SupplementalGroups is the strategy that will dictate what supplemental groups are used by the SecurityContext. + SupplementalGroups SupplementalGroupsStrategyOptions `json:"supplementalGroups" protobuf:"bytes,12,opt,name=supplementalGroups"` + // FSGroup is the strategy that will dictate what fs group is used by the SecurityContext. + FSGroup FSGroupStrategyOptions `json:"fsGroup" protobuf:"bytes,13,opt,name=fsGroup"` + // ReadOnlyRootFilesystem when set to true will force containers to run with a read only root file + // system. If the container specifically requests to run with a non-read only root file system + // the PSP should deny the pod. + // If set to false the container may run with a read only root file system if it wishes but it + // will not be forced to. + // +optional + ReadOnlyRootFilesystem bool `json:"readOnlyRootFilesystem,omitempty" protobuf:"varint,14,opt,name=readOnlyRootFilesystem"` + // DefaultAllowPrivilegeEscalation controls the default setting for whether a + // process can gain more privileges than its parent process. + // +optional + DefaultAllowPrivilegeEscalation *bool `json:"defaultAllowPrivilegeEscalation,omitempty" protobuf:"varint,15,opt,name=defaultAllowPrivilegeEscalation"` + // AllowPrivilegeEscalation determines if a pod can request to allow + // privilege escalation. If unspecified, defaults to true. + // +optional + AllowPrivilegeEscalation *bool `json:"allowPrivilegeEscalation,omitempty" protobuf:"varint,16,opt,name=allowPrivilegeEscalation"` + // is a white list of allowed host paths. Empty indicates that all host paths may be used. + // +optional + AllowedHostPaths []AllowedHostPath `json:"allowedHostPaths,omitempty" protobuf:"bytes,17,rep,name=allowedHostPaths"` + // AllowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all + // Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes + // is allowed in the "Volumes" field. + // +optional + AllowedFlexVolumes []AllowedFlexVolume `json:"allowedFlexVolumes,omitempty" protobuf:"bytes,18,rep,name=allowedFlexVolumes"` +} + +// defines the host volume conditions that will be enabled by a policy +// for pods to use. It requires the path prefix to be defined. +type AllowedHostPath struct { + // is the path prefix that the host volume must match. + // It does not support `*`. + // Trailing slashes are trimmed when validating the path prefix with a host path. + // + // Examples: + // `/foo` would allow `/foo`, `/foo/` and `/foo/bar` + // `/foo` would not allow `/food` or `/etc/foo` + PathPrefix string `json:"pathPrefix,omitempty" protobuf:"bytes,1,rep,name=pathPrefix"` +} + +// FS Type gives strong typing to different file systems that are used by volumes. +type FSType string + +var ( + AzureFile FSType = "azureFile" + Flocker FSType = "flocker" + FlexVolume FSType = "flexVolume" + HostPath FSType = "hostPath" + EmptyDir FSType = "emptyDir" + GCEPersistentDisk FSType = "gcePersistentDisk" + AWSElasticBlockStore FSType = "awsElasticBlockStore" + GitRepo FSType = "gitRepo" + Secret FSType = "secret" + NFS FSType = "nfs" + ISCSI FSType = "iscsi" + Glusterfs FSType = "glusterfs" + PersistentVolumeClaim FSType = "persistentVolumeClaim" + RBD FSType = "rbd" + Cinder FSType = "cinder" + CephFS FSType = "cephFS" + DownwardAPI FSType = "downwardAPI" + FC FSType = "fc" + ConfigMap FSType = "configMap" + Quobyte FSType = "quobyte" + AzureDisk FSType = "azureDisk" + All FSType = "*" +) + +// AllowedFlexVolume represents a single Flexvolume that is allowed to be used. +type AllowedFlexVolume struct { + // Driver is the name of the Flexvolume driver. + Driver string `json:"driver" protobuf:"bytes,1,opt,name=driver"` +} + +// Host Port Range defines a range of host ports that will be enabled by a policy +// for pods to use. It requires both the start and end to be defined. +type HostPortRange struct { + // min is the start of the range, inclusive. + Min int32 `json:"min" protobuf:"varint,1,opt,name=min"` + // max is the end of the range, inclusive. + Max int32 `json:"max" protobuf:"varint,2,opt,name=max"` +} + +// SELinux Strategy Options defines the strategy type and any options used to create the strategy. +type SELinuxStrategyOptions struct { + // type is the strategy that will dictate the allowable labels that may be set. + Rule SELinuxStrategy `json:"rule" protobuf:"bytes,1,opt,name=rule,casttype=SELinuxStrategy"` + // seLinuxOptions required to run as; required for MustRunAs + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + // +optional + SELinuxOptions *v1.SELinuxOptions `json:"seLinuxOptions,omitempty" protobuf:"bytes,2,opt,name=seLinuxOptions"` +} + +// SELinuxStrategy denotes strategy types for generating SELinux options for a +// Security Context. +type SELinuxStrategy string + +const ( + // container must have SELinux labels of X applied. + SELinuxStrategyMustRunAs SELinuxStrategy = "MustRunAs" + // container may make requests for any SELinux context labels. + SELinuxStrategyRunAsAny SELinuxStrategy = "RunAsAny" +) + +// Run A sUser Strategy Options defines the strategy type and any options used to create the strategy. +type RunAsUserStrategyOptions struct { + // Rule is the strategy that will dictate the allowable RunAsUser values that may be set. + Rule RunAsUserStrategy `json:"rule" protobuf:"bytes,1,opt,name=rule,casttype=RunAsUserStrategy"` + // Ranges are the allowed ranges of uids that may be used. + // +optional + Ranges []IDRange `json:"ranges,omitempty" protobuf:"bytes,2,rep,name=ranges"` +} + +// ID Range provides a min/max of an allowed range of IDs. +type IDRange struct { + // Min is the start of the range, inclusive. + Min int64 `json:"min" protobuf:"varint,1,opt,name=min"` + // Max is the end of the range, inclusive. + Max int64 `json:"max" protobuf:"varint,2,opt,name=max"` +} + +// RunAsUserStrategy denotes strategy types for generating RunAsUser values for a +// Security Context. +type RunAsUserStrategy string + +const ( + // container must run as a particular uid. + RunAsUserStrategyMustRunAs RunAsUserStrategy = "MustRunAs" + // container must run as a non-root uid + RunAsUserStrategyMustRunAsNonRoot RunAsUserStrategy = "MustRunAsNonRoot" + // container may make requests for any uid. + RunAsUserStrategyRunAsAny RunAsUserStrategy = "RunAsAny" +) + +// FSGroupStrategyOptions defines the strategy type and options used to create the strategy. +type FSGroupStrategyOptions struct { + // Rule is the strategy that will dictate what FSGroup is used in the SecurityContext. + // +optional + Rule FSGroupStrategyType `json:"rule,omitempty" protobuf:"bytes,1,opt,name=rule,casttype=FSGroupStrategyType"` + // Ranges are the allowed ranges of fs groups. If you would like to force a single + // fs group then supply a single range with the same start and end. + // +optional + Ranges []IDRange `json:"ranges,omitempty" protobuf:"bytes,2,rep,name=ranges"` +} + +// FSGroupStrategyType denotes strategy types for generating FSGroup values for a +// SecurityContext +type FSGroupStrategyType string + +const ( + // container must have FSGroup of X applied. + FSGroupStrategyMustRunAs FSGroupStrategyType = "MustRunAs" + // container may make requests for any FSGroup labels. + FSGroupStrategyRunAsAny FSGroupStrategyType = "RunAsAny" +) + +// SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy. +type SupplementalGroupsStrategyOptions struct { + // Rule is the strategy that will dictate what supplemental groups is used in the SecurityContext. + // +optional + Rule SupplementalGroupsStrategyType `json:"rule,omitempty" protobuf:"bytes,1,opt,name=rule,casttype=SupplementalGroupsStrategyType"` + // Ranges are the allowed ranges of supplemental groups. If you would like to force a single + // supplemental group then supply a single range with the same start and end. + // +optional + Ranges []IDRange `json:"ranges,omitempty" protobuf:"bytes,2,rep,name=ranges"` +} + +// SupplementalGroupsStrategyType denotes strategy types for determining valid supplemental +// groups for a SecurityContext. +type SupplementalGroupsStrategyType string + +const ( + // container must run as a particular gid. + SupplementalGroupsStrategyMustRunAs SupplementalGroupsStrategyType = "MustRunAs" + // container may make requests for any gid. + SupplementalGroupsStrategyRunAsAny SupplementalGroupsStrategyType = "RunAsAny" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Pod Security Policy List is a list of PodSecurityPolicy objects. +type PodSecurityPolicyList struct { + metav1.TypeMeta `json:",inline"` + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Items is a list of schema objects. + Items []PodSecurityPolicy `json:"items" protobuf:"bytes,2,rep,name=items"` +} diff --git a/test/integration/etcd/etcd_storage_path_test.go b/test/integration/etcd/etcd_storage_path_test.go index 13559eb8d0b..24c44ba62c3 100644 --- a/test/integration/etcd/etcd_storage_path_test.go +++ b/test/integration/etcd/etcd_storage_path_test.go @@ -296,6 +296,11 @@ var etcdStorageData = map[schema.GroupVersionResource]struct { stub: `{"metadata": {"name": "pdb1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`, expectedEtcdPath: "/registry/poddisruptionbudgets/etcdstoragepathtestnamespace/pdb1", }, + gvr("policy", "v1beta1", "podsecuritypolicies"): { + stub: `{"metadata": {"name": "psp2"}, "spec": {"fsGroup": {"rule": "RunAsAny"}, "privileged": true, "runAsUser": {"rule": "RunAsAny"}, "seLinux": {"rule": "MustRunAs"}, "supplementalGroups": {"rule": "RunAsAny"}}}`, + expectedEtcdPath: "/registry/podsecuritypolicy/psp2", + expectedGVK: gvkP("extensions", "v1beta1", "PodSecurityPolicy"), + }, // -- // k8s.io/kubernetes/pkg/apis/storage/v1alpha1