mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Enable Audit Logs Behind a Feature Gate
Audit logs are configurable via the MasterConfiguration file. All options are ignored unless the FeatureGate is enabled. Fixes kubernetes/kubeadm#623 Signed-off-by: Chuck Ha <ha.chuck@gmail.com>
This commit is contained in:
parent
1e1b32bf01
commit
ed769174bb
@ -111,6 +111,11 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
ConfigSyncPeriod: metav1.Duration{Duration: 1},
|
ConfigSyncPeriod: metav1.Duration{Duration: 1},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
obj.AuditPolicyConfiguration = kubeadm.AuditPolicyConfiguration{
|
||||||
|
Path: "foo",
|
||||||
|
LogDir: "/foo",
|
||||||
|
LogMaxAge: utilpointer.Int32Ptr(0),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
func(obj *kubeadm.NodeConfiguration, c fuzz.Continue) {
|
func(obj *kubeadm.NodeConfiguration, c fuzz.Continue) {
|
||||||
c.FuzzNoCustom(obj)
|
c.FuzzNoCustom(obj)
|
||||||
|
@ -104,6 +104,9 @@ type MasterConfiguration struct {
|
|||||||
// used for all control plane components.
|
// used for all control plane components.
|
||||||
UnifiedControlPlaneImage string
|
UnifiedControlPlaneImage string
|
||||||
|
|
||||||
|
// AuditPolicyConfiguration defines the options for the api server audit system.
|
||||||
|
AuditPolicyConfiguration AuditPolicyConfiguration
|
||||||
|
|
||||||
// FeatureGates enabled by the user.
|
// FeatureGates enabled by the user.
|
||||||
FeatureGates map[string]bool
|
FeatureGates map[string]bool
|
||||||
}
|
}
|
||||||
@ -259,3 +262,14 @@ type HostPathMount struct {
|
|||||||
type KubeProxy struct {
|
type KubeProxy struct {
|
||||||
Config *kubeproxyconfigv1alpha1.KubeProxyConfiguration
|
Config *kubeproxyconfigv1alpha1.KubeProxyConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuditPolicyConfiguration holds the options for configuring the api server audit policy.
|
||||||
|
type AuditPolicyConfiguration struct {
|
||||||
|
// Path is the local path to an audit policy.
|
||||||
|
Path string
|
||||||
|
// LogDir is the local path to the directory where logs should be stored.
|
||||||
|
LogDir string
|
||||||
|
// LogMaxAge is the number of days logs will be stored for. 0 indicates forever.
|
||||||
|
LogMaxAge *int32
|
||||||
|
//TODO(chuckha) add other options for audit policy.
|
||||||
|
}
|
||||||
|
@ -69,6 +69,12 @@ const (
|
|||||||
KubeproxyKubeConfigFileName = "/var/lib/kube-proxy/kubeconfig.conf"
|
KubeproxyKubeConfigFileName = "/var/lib/kube-proxy/kubeconfig.conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultAuditPolicyLogMaxAge is defined as a var so its address can be taken
|
||||||
|
// It is the number of days to store audit logs
|
||||||
|
DefaultAuditPolicyLogMaxAge = int32(2)
|
||||||
|
)
|
||||||
|
|
||||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||||
return RegisterDefaults(scheme)
|
return RegisterDefaults(scheme)
|
||||||
}
|
}
|
||||||
@ -118,6 +124,7 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
|
|||||||
SetDefaults_KubeletConfiguration(obj)
|
SetDefaults_KubeletConfiguration(obj)
|
||||||
}
|
}
|
||||||
SetDefaults_ProxyConfiguration(obj)
|
SetDefaults_ProxyConfiguration(obj)
|
||||||
|
SetDefaults_AuditPolicyConfiguration(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults_ProxyConfiguration assigns default values for the Proxy
|
// SetDefaults_ProxyConfiguration assigns default values for the Proxy
|
||||||
@ -211,3 +218,13 @@ func SetDefaults_KubeletConfiguration(obj *MasterConfiguration) {
|
|||||||
scheme.Default(obj.KubeletConfiguration.BaseConfig)
|
scheme.Default(obj.KubeletConfiguration.BaseConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDefaults_AuditPolicyConfiguration sets default values for the AuditPolicyConfiguration
|
||||||
|
func SetDefaults_AuditPolicyConfiguration(obj *MasterConfiguration) {
|
||||||
|
if obj.AuditPolicyConfiguration.LogDir == "" {
|
||||||
|
obj.AuditPolicyConfiguration.LogDir = constants.StaticPodAuditPolicyLogDir
|
||||||
|
}
|
||||||
|
if obj.AuditPolicyConfiguration.LogMaxAge == nil {
|
||||||
|
obj.AuditPolicyConfiguration.LogMaxAge = &DefaultAuditPolicyLogMaxAge
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -97,6 +97,9 @@ type MasterConfiguration struct {
|
|||||||
// be used for all control plane components.
|
// be used for all control plane components.
|
||||||
UnifiedControlPlaneImage string `json:"unifiedControlPlaneImage"`
|
UnifiedControlPlaneImage string `json:"unifiedControlPlaneImage"`
|
||||||
|
|
||||||
|
// AuditPolicyConfiguration defines the options for the api server audit system
|
||||||
|
AuditPolicyConfiguration AuditPolicyConfiguration `json:"auditPolicy"`
|
||||||
|
|
||||||
// FeatureGates enabled by the user.
|
// FeatureGates enabled by the user.
|
||||||
FeatureGates map[string]bool `json:"featureGates,omitempty"`
|
FeatureGates map[string]bool `json:"featureGates,omitempty"`
|
||||||
}
|
}
|
||||||
@ -240,3 +243,14 @@ type HostPathMount struct {
|
|||||||
type KubeProxy struct {
|
type KubeProxy struct {
|
||||||
Config *kubeproxyconfigv1alpha1.KubeProxyConfiguration `json:"config,omitempty"`
|
Config *kubeproxyconfigv1alpha1.KubeProxyConfiguration `json:"config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuditPolicyConfiguration holds the options for configuring the api server audit policy.
|
||||||
|
type AuditPolicyConfiguration struct {
|
||||||
|
// Path is the local path to an audit policy.
|
||||||
|
Path string `json:"path"`
|
||||||
|
// LogDir is the local path to the directory where logs should be stored.
|
||||||
|
LogDir string `json:"logDir"`
|
||||||
|
// LogMaxAge is the number of days logs will be stored for. 0 indicates forever.
|
||||||
|
LogMaxAge *int32 `json:"logMaxAge,omitempty"`
|
||||||
|
//TODO(chuckha) add other options for audit policy.
|
||||||
|
}
|
||||||
|
@ -41,6 +41,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
|||||||
return scheme.AddGeneratedConversionFuncs(
|
return scheme.AddGeneratedConversionFuncs(
|
||||||
Convert_v1alpha1_API_To_kubeadm_API,
|
Convert_v1alpha1_API_To_kubeadm_API,
|
||||||
Convert_kubeadm_API_To_v1alpha1_API,
|
Convert_kubeadm_API_To_v1alpha1_API,
|
||||||
|
Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration,
|
||||||
|
Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration,
|
||||||
Convert_v1alpha1_Etcd_To_kubeadm_Etcd,
|
Convert_v1alpha1_Etcd_To_kubeadm_Etcd,
|
||||||
Convert_kubeadm_Etcd_To_v1alpha1_Etcd,
|
Convert_kubeadm_Etcd_To_v1alpha1_Etcd,
|
||||||
Convert_v1alpha1_HostPathMount_To_kubeadm_HostPathMount,
|
Convert_v1alpha1_HostPathMount_To_kubeadm_HostPathMount,
|
||||||
@ -84,6 +86,30 @@ func Convert_kubeadm_API_To_v1alpha1_API(in *kubeadm.API, out *API, s conversion
|
|||||||
return autoConvert_kubeadm_API_To_v1alpha1_API(in, out, s)
|
return autoConvert_kubeadm_API_To_v1alpha1_API(in, out, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(in *AuditPolicyConfiguration, out *kubeadm.AuditPolicyConfiguration, s conversion.Scope) error {
|
||||||
|
out.Path = in.Path
|
||||||
|
out.LogDir = in.LogDir
|
||||||
|
out.LogMaxAge = (*int32)(unsafe.Pointer(in.LogMaxAge))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(in *AuditPolicyConfiguration, out *kubeadm.AuditPolicyConfiguration, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(in *kubeadm.AuditPolicyConfiguration, out *AuditPolicyConfiguration, s conversion.Scope) error {
|
||||||
|
out.Path = in.Path
|
||||||
|
out.LogDir = in.LogDir
|
||||||
|
out.LogMaxAge = (*int32)(unsafe.Pointer(in.LogMaxAge))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration is an autogenerated conversion function.
|
||||||
|
func Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(in *kubeadm.AuditPolicyConfiguration, out *AuditPolicyConfiguration, s conversion.Scope) error {
|
||||||
|
return autoConvert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
func autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
|
func autoConvert_v1alpha1_Etcd_To_kubeadm_Etcd(in *Etcd, out *kubeadm.Etcd, s conversion.Scope) error {
|
||||||
out.Endpoints = *(*[]string)(unsafe.Pointer(&in.Endpoints))
|
out.Endpoints = *(*[]string)(unsafe.Pointer(&in.Endpoints))
|
||||||
out.CAFile = in.CAFile
|
out.CAFile = in.CAFile
|
||||||
@ -215,6 +241,9 @@ func autoConvert_v1alpha1_MasterConfiguration_To_kubeadm_MasterConfiguration(in
|
|||||||
out.CertificatesDir = in.CertificatesDir
|
out.CertificatesDir = in.CertificatesDir
|
||||||
out.ImageRepository = in.ImageRepository
|
out.ImageRepository = in.ImageRepository
|
||||||
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
|
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
|
||||||
|
if err := Convert_v1alpha1_AuditPolicyConfiguration_To_kubeadm_AuditPolicyConfiguration(&in.AuditPolicyConfiguration, &out.AuditPolicyConfiguration, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
|
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -258,6 +287,9 @@ func autoConvert_kubeadm_MasterConfiguration_To_v1alpha1_MasterConfiguration(in
|
|||||||
out.ImageRepository = in.ImageRepository
|
out.ImageRepository = in.ImageRepository
|
||||||
// INFO: in.CIImageRepository opted out of conversion generation
|
// INFO: in.CIImageRepository opted out of conversion generation
|
||||||
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
|
out.UnifiedControlPlaneImage = in.UnifiedControlPlaneImage
|
||||||
|
if err := Convert_kubeadm_AuditPolicyConfiguration_To_v1alpha1_AuditPolicyConfiguration(&in.AuditPolicyConfiguration, &out.AuditPolicyConfiguration, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
|
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,31 @@ func (in *API) DeepCopy() *API {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *AuditPolicyConfiguration) DeepCopyInto(out *AuditPolicyConfiguration) {
|
||||||
|
*out = *in
|
||||||
|
if in.LogMaxAge != nil {
|
||||||
|
in, out := &in.LogMaxAge, &out.LogMaxAge
|
||||||
|
if *in == nil {
|
||||||
|
*out = nil
|
||||||
|
} else {
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuditPolicyConfiguration.
|
||||||
|
func (in *AuditPolicyConfiguration) DeepCopy() *AuditPolicyConfiguration {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(AuditPolicyConfiguration)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// 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 *Etcd) DeepCopyInto(out *Etcd) {
|
func (in *Etcd) DeepCopyInto(out *Etcd) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -210,6 +235,7 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) {
|
|||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
|
in.AuditPolicyConfiguration.DeepCopyInto(&out.AuditPolicyConfiguration)
|
||||||
if in.FeatureGates != nil {
|
if in.FeatureGates != nil {
|
||||||
in, out := &in.FeatureGates, &out.FeatureGates
|
in, out := &in.FeatureGates, &out.FeatureGates
|
||||||
*out = make(map[string]bool, len(*in))
|
*out = make(map[string]bool, len(*in))
|
||||||
|
@ -43,6 +43,31 @@ func (in *API) DeepCopy() *API {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *AuditPolicyConfiguration) DeepCopyInto(out *AuditPolicyConfiguration) {
|
||||||
|
*out = *in
|
||||||
|
if in.LogMaxAge != nil {
|
||||||
|
in, out := &in.LogMaxAge, &out.LogMaxAge
|
||||||
|
if *in == nil {
|
||||||
|
*out = nil
|
||||||
|
} else {
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuditPolicyConfiguration.
|
||||||
|
func (in *AuditPolicyConfiguration) DeepCopy() *AuditPolicyConfiguration {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(AuditPolicyConfiguration)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// 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 *Etcd) DeepCopyInto(out *Etcd) {
|
func (in *Etcd) DeepCopyInto(out *Etcd) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -210,6 +235,7 @@ func (in *MasterConfiguration) DeepCopyInto(out *MasterConfiguration) {
|
|||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
|
in.AuditPolicyConfiguration.DeepCopyInto(&out.AuditPolicyConfiguration)
|
||||||
if in.FeatureGates != nil {
|
if in.FeatureGates != nil {
|
||||||
in, out := &in.FeatureGates, &out.FeatureGates
|
in, out := &in.FeatureGates, &out.FeatureGates
|
||||||
*out = make(map[string]bool, len(*in))
|
*out = make(map[string]bool, len(*in))
|
||||||
|
@ -47,6 +47,7 @@ go_library(
|
|||||||
"//cmd/kubeadm/app/preflight:go_default_library",
|
"//cmd/kubeadm/app/preflight:go_default_library",
|
||||||
"//cmd/kubeadm/app/util:go_default_library",
|
"//cmd/kubeadm/app/util:go_default_library",
|
||||||
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
"//cmd/kubeadm/app/util/apiclient:go_default_library",
|
||||||
|
"//cmd/kubeadm/app/util/audit:go_default_library",
|
||||||
"//cmd/kubeadm/app/util/config:go_default_library",
|
"//cmd/kubeadm/app/util/config:go_default_library",
|
||||||
"//cmd/kubeadm/app/util/dryrun:go_default_library",
|
"//cmd/kubeadm/app/util/dryrun:go_default_library",
|
||||||
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
||||||
|
@ -56,6 +56,7 @@ import (
|
|||||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||||
|
auditutil "k8s.io/kubernetes/cmd/kubeadm/app/util/audit"
|
||||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||||
dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
|
dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
|
||||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||||
@ -319,6 +320,21 @@ func (i *Init) Run(out io.Writer) error {
|
|||||||
fmt.Println("[externalca] The file 'ca.key' was not found, yet all other certificates are present. Using external CA mode - certificates or kubeconfig will not be generated.")
|
fmt.Println("[externalca] The file 'ca.key' was not found, yet all other certificates are present. Using external CA mode - certificates or kubeconfig will not be generated.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if features.Enabled(i.cfg.FeatureGates, features.Auditing) {
|
||||||
|
// Setup the AuditPolicy (either it was passed in and exists or it wasn't passed in and generate a default policy)
|
||||||
|
if i.cfg.AuditPolicyConfiguration.Path != "" {
|
||||||
|
// TODO(chuckha) ensure passed in audit policy is valid so users don't have to find the error in the api server log.
|
||||||
|
if _, err := os.Stat(i.cfg.AuditPolicyConfiguration.Path); err != nil {
|
||||||
|
return fmt.Errorf("error getting file info for audit policy file %q [%v]", i.cfg.AuditPolicyConfiguration.Path, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i.cfg.AuditPolicyConfiguration.Path = filepath.Join(kubeConfigDir, kubeadmconstants.AuditPolicyDir, kubeadmconstants.AuditPolicyFile)
|
||||||
|
if err := auditutil.CreateDefaultAuditLogPolicy(i.cfg.AuditPolicyConfiguration.Path); err != nil {
|
||||||
|
return fmt.Errorf("error creating default audit policy %q [%v]", i.cfg.AuditPolicyConfiguration.Path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Temporarily set cfg.CertificatesDir to the "real value" when writing controlplane manifests
|
// Temporarily set cfg.CertificatesDir to the "real value" when writing controlplane manifests
|
||||||
// This is needed for writing the right kind of manifests
|
// This is needed for writing the right kind of manifests
|
||||||
i.cfg.CertificatesDir = realCertsDir
|
i.cfg.CertificatesDir = realCertsDir
|
||||||
|
@ -41,6 +41,9 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
api:
|
api:
|
||||||
advertiseAddress: ""
|
advertiseAddress: ""
|
||||||
bindPort: 0
|
bindPort: 0
|
||||||
|
auditPolicy:
|
||||||
|
logDir: ""
|
||||||
|
path: ""
|
||||||
certificatesDir: ""
|
certificatesDir: ""
|
||||||
cloudProvider: ""
|
cloudProvider: ""
|
||||||
etcd:
|
etcd:
|
||||||
@ -75,6 +78,9 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
api:
|
api:
|
||||||
advertiseAddress: ""
|
advertiseAddress: ""
|
||||||
bindPort: 0
|
bindPort: 0
|
||||||
|
auditPolicy:
|
||||||
|
logDir: ""
|
||||||
|
path: ""
|
||||||
certificatesDir: ""
|
certificatesDir: ""
|
||||||
cloudProvider: ""
|
cloudProvider: ""
|
||||||
etcd:
|
etcd:
|
||||||
@ -114,6 +120,9 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
api:
|
api:
|
||||||
advertiseAddress: ""
|
advertiseAddress: ""
|
||||||
bindPort: 0
|
bindPort: 0
|
||||||
|
auditPolicy:
|
||||||
|
logDir: ""
|
||||||
|
path: ""
|
||||||
certificatesDir: ""
|
certificatesDir: ""
|
||||||
cloudProvider: ""
|
cloudProvider: ""
|
||||||
etcd:
|
etcd:
|
||||||
|
@ -203,6 +203,19 @@ const (
|
|||||||
|
|
||||||
// CRICtlPackage defines the go package that installs crictl
|
// CRICtlPackage defines the go package that installs crictl
|
||||||
CRICtlPackage = "github.com/kubernetes-incubator/cri-tools/cmd/crictl"
|
CRICtlPackage = "github.com/kubernetes-incubator/cri-tools/cmd/crictl"
|
||||||
|
|
||||||
|
// KubeAuditPolicyVolumeName is the name of the volume that will contain the audit policy
|
||||||
|
KubeAuditPolicyVolumeName = "audit"
|
||||||
|
// AuditPolicyDir is the directory that will contain the audit policy
|
||||||
|
AuditPolicyDir = "audit"
|
||||||
|
// AuditPolicyFile is the name of the audit policy file itself
|
||||||
|
AuditPolicyFile = "audit.yaml"
|
||||||
|
// AuditPolicyLogFile is the name of the file audit logs get written to
|
||||||
|
AuditPolicyLogFile = "audit.log"
|
||||||
|
// KubeAuditPolicyLogVolumeName is the name of the volume that will contain the audit logs
|
||||||
|
KubeAuditPolicyLogVolumeName = "audit-log"
|
||||||
|
// StaticPodAuditPolicyLogDir is the name of the directory in the static pod that will have the audit logs
|
||||||
|
StaticPodAuditPolicyLogDir = "/var/log/kubernetes/audit"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -311,3 +324,8 @@ func GetDNSIP(svcSubnet string) (net.IP, error) {
|
|||||||
|
|
||||||
return dnsIP, nil
|
return dnsIP, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStaticPodAuditPolicyFile returns the path to the audit policy file within a static pod
|
||||||
|
func GetStaticPodAuditPolicyFile() string {
|
||||||
|
return filepath.Join(KubernetesDir, AuditPolicyDir, AuditPolicyFile)
|
||||||
|
}
|
||||||
|
@ -41,6 +41,9 @@ const (
|
|||||||
|
|
||||||
// DynamicKubeletConfig is alpha in v1.9
|
// DynamicKubeletConfig is alpha in v1.9
|
||||||
DynamicKubeletConfig = "DynamicKubeletConfig"
|
DynamicKubeletConfig = "DynamicKubeletConfig"
|
||||||
|
|
||||||
|
// Auditing is beta in 1.8
|
||||||
|
Auditing = "Auditing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var v190 = version.MustParseSemantic("v1.9.0-alpha.1")
|
var v190 = version.MustParseSemantic("v1.9.0-alpha.1")
|
||||||
@ -53,6 +56,7 @@ var InitFeatureGates = FeatureList{
|
|||||||
HighAvailability: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190, HiddenInHelpText: true},
|
HighAvailability: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190, HiddenInHelpText: true},
|
||||||
CoreDNS: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
|
CoreDNS: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
|
||||||
DynamicKubeletConfig: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
|
DynamicKubeletConfig: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
|
||||||
|
Auditing: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Feature represents a feature being gated
|
// Feature represents a feature being gated
|
||||||
|
@ -21,6 +21,7 @@ go_test(
|
|||||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||||
"//cmd/kubeadm/test:go_default_library",
|
"//cmd/kubeadm/test:go_default_library",
|
||||||
"//pkg/master/reconcilers:go_default_library",
|
"//pkg/master/reconcilers:go_default_library",
|
||||||
|
"//pkg/util/pointer:go_default_library",
|
||||||
"//pkg/util/version:go_default_library",
|
"//pkg/util/version:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
],
|
],
|
||||||
|
@ -221,6 +221,16 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, k8sVersion *versio
|
|||||||
command = append(command, "--feature-gates=DynamicKubeletConfig=true")
|
command = append(command, "--feature-gates=DynamicKubeletConfig=true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if features.Enabled(cfg.FeatureGates, features.Auditing) {
|
||||||
|
command = append(command, "--audit-policy-file="+kubeadmconstants.GetStaticPodAuditPolicyFile())
|
||||||
|
command = append(command, "--audit-log-path="+filepath.Join(kubeadmconstants.StaticPodAuditPolicyLogDir, kubeadmconstants.AuditPolicyLogFile))
|
||||||
|
if cfg.AuditPolicyConfiguration.LogMaxAge == nil {
|
||||||
|
command = append(command, fmt.Sprintf("--audit-log-maxage=%d", kubeadmapiext.DefaultAuditPolicyLogMaxAge))
|
||||||
|
} else {
|
||||||
|
command = append(command, fmt.Sprintf("--audit-log-maxage=%d", *cfg.AuditPolicyConfiguration.LogMaxAge))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/version"
|
"k8s.io/kubernetes/pkg/util/version"
|
||||||
|
|
||||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||||
|
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -338,6 +339,11 @@ func TestGetAPIServerCommand(t *testing.T) {
|
|||||||
Etcd: kubeadmapi.Etcd{CertFile: "fiz", KeyFile: "faz"},
|
Etcd: kubeadmapi.Etcd{CertFile: "fiz", KeyFile: "faz"},
|
||||||
CertificatesDir: testCertsDir,
|
CertificatesDir: testCertsDir,
|
||||||
KubernetesVersion: "v1.9.3",
|
KubernetesVersion: "v1.9.3",
|
||||||
|
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
|
||||||
|
Path: "/foo/bar",
|
||||||
|
LogDir: "/foo/baz",
|
||||||
|
LogMaxAge: utilpointer.Int32Ptr(10),
|
||||||
|
}, // ignored without the feature gate
|
||||||
},
|
},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"kube-apiserver",
|
"kube-apiserver",
|
||||||
@ -446,9 +452,12 @@ func TestGetAPIServerCommand(t *testing.T) {
|
|||||||
cfg: &kubeadmapi.MasterConfiguration{
|
cfg: &kubeadmapi.MasterConfiguration{
|
||||||
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
API: kubeadmapi.API{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
|
||||||
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
|
||||||
FeatureGates: map[string]bool{features.HighAvailability: true},
|
FeatureGates: map[string]bool{features.HighAvailability: true, features.Auditing: true},
|
||||||
CertificatesDir: testCertsDir,
|
CertificatesDir: testCertsDir,
|
||||||
KubernetesVersion: "v1.9.0-beta.0",
|
KubernetesVersion: "v1.9.0-beta.0",
|
||||||
|
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
|
||||||
|
LogMaxAge: utilpointer.Int32Ptr(0),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"kube-apiserver",
|
"kube-apiserver",
|
||||||
@ -476,6 +485,9 @@ func TestGetAPIServerCommand(t *testing.T) {
|
|||||||
"--advertise-address=2001:db8::1",
|
"--advertise-address=2001:db8::1",
|
||||||
"--etcd-servers=http://127.0.0.1:2379",
|
"--etcd-servers=http://127.0.0.1:2379",
|
||||||
fmt.Sprintf("--endpoint-reconciler-type=%s", reconcilers.LeaseEndpointReconcilerType),
|
fmt.Sprintf("--endpoint-reconciler-type=%s", reconcilers.LeaseEndpointReconcilerType),
|
||||||
|
"--audit-policy-file=/etc/kubernetes/audit/audit.yaml",
|
||||||
|
"--audit-log-path=/var/log/kubernetes/audit/audit.log",
|
||||||
|
"--audit-log-maxage=0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||||
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
|
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ var caCertsPkiVolumePath = "/etc/pki"
|
|||||||
func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) controlPlaneHostPathMounts {
|
func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) controlPlaneHostPathMounts {
|
||||||
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
|
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
|
||||||
hostPathFileOrCreate := v1.HostPathFileOrCreate
|
hostPathFileOrCreate := v1.HostPathFileOrCreate
|
||||||
|
hostPathFile := v1.HostPathFile
|
||||||
mounts := newControlPlaneHostPathMounts()
|
mounts := newControlPlaneHostPathMounts()
|
||||||
|
|
||||||
// HostPath volumes for the API Server
|
// HostPath volumes for the API Server
|
||||||
@ -55,7 +57,12 @@ func getHostPathVolumesForTheControlPlane(cfg *kubeadmapi.MasterConfiguration) c
|
|||||||
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeCertificatesVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true, &hostPathDirectoryOrCreate)
|
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeCertificatesVolumeName, cfg.CertificatesDir, cfg.CertificatesDir, true, &hostPathDirectoryOrCreate)
|
||||||
// Read-only mount for the ca certs (/etc/ssl/certs) directory
|
// Read-only mount for the ca certs (/etc/ssl/certs) directory
|
||||||
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true, &hostPathDirectoryOrCreate)
|
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, caCertsVolumeName, caCertsVolumePath, caCertsVolumePath, true, &hostPathDirectoryOrCreate)
|
||||||
|
if features.Enabled(cfg.FeatureGates, features.Auditing) {
|
||||||
|
// Read-only mount for the audit policy file.
|
||||||
|
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeAuditPolicyVolumeName, cfg.AuditPolicyConfiguration.Path, kubeadmconstants.GetStaticPodAuditPolicyFile(), true, &hostPathFile)
|
||||||
|
// Write mount for the audit logs.
|
||||||
|
mounts.NewHostPathMount(kubeadmconstants.KubeAPIServer, kubeadmconstants.KubeAuditPolicyLogVolumeName, cfg.AuditPolicyConfiguration.LogDir, kubeadmconstants.StaticPodAuditPolicyLogDir, false, &hostPathDirectoryOrCreate)
|
||||||
|
}
|
||||||
// If external etcd is specified, mount the directories needed for accessing the CA/serving certs and the private key
|
// If external etcd is specified, mount the directories needed for accessing the CA/serving certs and the private key
|
||||||
if len(cfg.Etcd.Endpoints) != 0 {
|
if len(cfg.Etcd.Endpoints) != 0 {
|
||||||
etcdVols, etcdVolMounts := getEtcdCertVolumes(cfg.Etcd, cfg.CertificatesDir)
|
etcdVols, etcdVolMounts := getEtcdCertVolumes(cfg.Etcd, cfg.CertificatesDir)
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetEtcdCertVolumes(t *testing.T) {
|
func TestGetEtcdCertVolumes(t *testing.T) {
|
||||||
@ -258,6 +259,7 @@ func TestGetEtcdCertVolumes(t *testing.T) {
|
|||||||
func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
||||||
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
|
hostPathDirectoryOrCreate := v1.HostPathDirectoryOrCreate
|
||||||
hostPathFileOrCreate := v1.HostPathFileOrCreate
|
hostPathFileOrCreate := v1.HostPathFileOrCreate
|
||||||
|
hostPathFile := v1.HostPathFile
|
||||||
volMap := make(map[string]map[string]v1.Volume)
|
volMap := make(map[string]map[string]v1.Volume)
|
||||||
volMap[kubeadmconstants.KubeAPIServer] = map[string]v1.Volume{}
|
volMap[kubeadmconstants.KubeAPIServer] = map[string]v1.Volume{}
|
||||||
volMap[kubeadmconstants.KubeAPIServer]["k8s-certs"] = v1.Volume{
|
volMap[kubeadmconstants.KubeAPIServer]["k8s-certs"] = v1.Volume{
|
||||||
@ -278,6 +280,24 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
volMap[kubeadmconstants.KubeAPIServer]["audit"] = v1.Volume{
|
||||||
|
Name: "audit",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
HostPath: &v1.HostPathVolumeSource{
|
||||||
|
Path: "/foo/bar/baz.yaml",
|
||||||
|
Type: &hostPathFile,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
volMap[kubeadmconstants.KubeAPIServer]["audit-log"] = v1.Volume{
|
||||||
|
Name: "audit-log",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
HostPath: &v1.HostPathVolumeSource{
|
||||||
|
Path: "/bar/foo",
|
||||||
|
Type: &hostPathDirectoryOrCreate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
volMap[kubeadmconstants.KubeControllerManager] = map[string]v1.Volume{}
|
volMap[kubeadmconstants.KubeControllerManager] = map[string]v1.Volume{}
|
||||||
volMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.Volume{
|
volMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.Volume{
|
||||||
Name: "k8s-certs",
|
Name: "k8s-certs",
|
||||||
@ -328,6 +348,16 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
|||||||
MountPath: "/etc/ssl/certs",
|
MountPath: "/etc/ssl/certs",
|
||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
}
|
}
|
||||||
|
volMountMap[kubeadmconstants.KubeAPIServer]["audit"] = v1.VolumeMount{
|
||||||
|
Name: "audit",
|
||||||
|
MountPath: "/etc/kubernetes/audit/audit.yaml",
|
||||||
|
ReadOnly: true,
|
||||||
|
}
|
||||||
|
volMountMap[kubeadmconstants.KubeAPIServer]["audit-log"] = v1.VolumeMount{
|
||||||
|
Name: "audit-log",
|
||||||
|
MountPath: "/var/log/kubernetes/audit",
|
||||||
|
ReadOnly: false,
|
||||||
|
}
|
||||||
volMountMap[kubeadmconstants.KubeControllerManager] = map[string]v1.VolumeMount{}
|
volMountMap[kubeadmconstants.KubeControllerManager] = map[string]v1.VolumeMount{}
|
||||||
volMountMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.VolumeMount{
|
volMountMap[kubeadmconstants.KubeControllerManager]["k8s-certs"] = v1.VolumeMount{
|
||||||
Name: "k8s-certs",
|
Name: "k8s-certs",
|
||||||
@ -481,6 +511,11 @@ func TestGetHostPathVolumesForTheControlPlane(t *testing.T) {
|
|||||||
cfg: &kubeadmapi.MasterConfiguration{
|
cfg: &kubeadmapi.MasterConfiguration{
|
||||||
CertificatesDir: testCertsDir,
|
CertificatesDir: testCertsDir,
|
||||||
Etcd: kubeadmapi.Etcd{},
|
Etcd: kubeadmapi.Etcd{},
|
||||||
|
FeatureGates: map[string]bool{features.Auditing: true},
|
||||||
|
AuditPolicyConfiguration: kubeadmapi.AuditPolicyConfiguration{
|
||||||
|
Path: "/foo/bar/baz.yaml",
|
||||||
|
LogDir: "/bar/foo",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
vol: volMap,
|
vol: volMap,
|
||||||
volMount: volMountMap,
|
volMount: volMountMap,
|
||||||
|
@ -61,6 +61,7 @@ filegroup(
|
|||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//cmd/kubeadm/app/util/apiclient:all-srcs",
|
"//cmd/kubeadm/app/util/apiclient:all-srcs",
|
||||||
|
"//cmd/kubeadm/app/util/audit:all-srcs",
|
||||||
"//cmd/kubeadm/app/util/config:all-srcs",
|
"//cmd/kubeadm/app/util/config:all-srcs",
|
||||||
"//cmd/kubeadm/app/util/dryrun:all-srcs",
|
"//cmd/kubeadm/app/util/dryrun:all-srcs",
|
||||||
"//cmd/kubeadm/app/util/kubeconfig:all-srcs",
|
"//cmd/kubeadm/app/util/kubeconfig:all-srcs",
|
||||||
|
40
cmd/kubeadm/app/util/audit/BUILD
Normal file
40
cmd/kubeadm/app/util/audit/BUILD
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["utils.go"],
|
||||||
|
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/audit",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//cmd/kubeadm/app/util:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||||
|
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = ["utils_test.go"],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/util/audit",
|
||||||
|
deps = [
|
||||||
|
"//pkg/kubectl/scheme:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
67
cmd/kubeadm/app/util/audit/utils.go
Normal file
67
cmd/kubeadm/app/util/audit/utils.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
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 audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateDefaultAuditLogPolicy writes the default audit log policy to disk.
|
||||||
|
func CreateDefaultAuditLogPolicy(policyFile string) error {
|
||||||
|
policy := auditv1beta1.Policy{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "audit.k8s.io/v1beta1",
|
||||||
|
Kind: "Policy",
|
||||||
|
},
|
||||||
|
Rules: []auditv1beta1.PolicyRule{
|
||||||
|
{
|
||||||
|
Level: auditv1beta1.LevelMetadata,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return writePolicyToDisk(policyFile, &policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writePolicyToDisk(policyFile string, policy *auditv1beta1.Policy) error {
|
||||||
|
// creates target folder if not already exists
|
||||||
|
if err := os.MkdirAll(filepath.Dir(policyFile), 0700); err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory %q: %v", filepath.Dir(policyFile), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registers auditv1beta1 with the runtime Scheme
|
||||||
|
auditv1beta1.AddToScheme(scheme.Scheme)
|
||||||
|
|
||||||
|
// writes the policy to disk
|
||||||
|
serialized, err := util.MarshalToYaml(policy, auditv1beta1.SchemeGroupVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal audit policy to YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(policyFile, serialized, 0600); err != nil {
|
||||||
|
return fmt.Errorf("failed to write audit policy to %v: %v", policyFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
61
cmd/kubeadm/app/util/audit/utils_test.go
Normal file
61
cmd/kubeadm/app/util/audit/utils_test.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
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 audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
auditv1beta1 "k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cleanup(t *testing.T, path string) {
|
||||||
|
err := os.RemoveAll(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to clean up %v: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateDefaultAuditLogPolicy(t *testing.T) {
|
||||||
|
// make a tempdir
|
||||||
|
tempDir, err := ioutil.TempDir("/tmp", "audit-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not create a tempdir: %v", err)
|
||||||
|
}
|
||||||
|
defer cleanup(t, tempDir)
|
||||||
|
auditPolicyFile := filepath.Join(tempDir, "test.yaml")
|
||||||
|
if err = CreateDefaultAuditLogPolicy(auditPolicyFile); err != nil {
|
||||||
|
t.Fatalf("failed to create audit log policy: %v", err)
|
||||||
|
}
|
||||||
|
// turn the audit log back into a policy
|
||||||
|
policyBytes, err := ioutil.ReadFile(auditPolicyFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read %v: %v", auditPolicyFile, err)
|
||||||
|
}
|
||||||
|
policy := auditv1beta1.Policy{}
|
||||||
|
err = runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), policyBytes, &policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to decode written policy: %v", err)
|
||||||
|
}
|
||||||
|
if policy.Kind != "Policy" {
|
||||||
|
t.Fatalf("did not decode policy properly")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user