From 48d0f8c98b3511875768085af12c21389a465ab4 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorek Date: Thu, 26 Sep 2019 12:31:56 +0200 Subject: k8s: Declutter checker by dividing it into smaller packages Issue-ID: SECCOM-235 Change-Id: I7d4efd08b8c0258f2f9c33772bf1b1b02cedebfa Signed-off-by: Pawel Wieczorek --- test/security/k8s/src/check/cmd/check/check.go | 47 +- .../k8s/src/check/validators/master/api.go | 391 ---------------- .../k8s/src/check/validators/master/api/api.go | 391 ++++++++++++++++ .../check/validators/master/api/api_suite_test.go | 13 + .../src/check/validators/master/api/api_test.go | 518 +++++++++++++++++++++ .../k8s/src/check/validators/master/api_test.go | 518 --------------------- .../k8s/src/check/validators/master/master.go | 57 +++ .../check/validators/master/master_suite_test.go | 13 - 8 files changed, 980 insertions(+), 968 deletions(-) delete mode 100644 test/security/k8s/src/check/validators/master/api.go create mode 100644 test/security/k8s/src/check/validators/master/api/api.go create mode 100644 test/security/k8s/src/check/validators/master/api/api_suite_test.go create mode 100644 test/security/k8s/src/check/validators/master/api/api_test.go delete mode 100644 test/security/k8s/src/check/validators/master/api_test.go create mode 100644 test/security/k8s/src/check/validators/master/master.go delete mode 100644 test/security/k8s/src/check/validators/master/master_suite_test.go diff --git a/test/security/k8s/src/check/cmd/check/check.go b/test/security/k8s/src/check/cmd/check/check.go index b10b8cb1d..5a29fa9d5 100644 --- a/test/security/k8s/src/check/cmd/check/check.go +++ b/test/security/k8s/src/check/cmd/check/check.go @@ -38,50 +38,5 @@ func main() { log.Fatal(err) } - log.Printf("IsBasicAuthFileAbsent: %t\n", master.IsBasicAuthFileAbsent(k8sParams)) - log.Printf("IsTokenAuthFileAbsent: %t\n", master.IsTokenAuthFileAbsent(k8sParams)) - log.Printf("IsInsecureAllowAnyTokenAbsent: %t\n", master.IsInsecureAllowAnyTokenAbsent(k8sParams)) - - log.Printf("IsAnonymousAuthDisabled: %t\n", master.IsAnonymousAuthDisabled(k8sParams)) - log.Printf("IsInsecurePortUnbound: %t\n", master.IsInsecurePortUnbound(k8sParams)) - log.Printf("IsProfilingDisabled: %t\n", master.IsProfilingDisabled(k8sParams)) - log.Printf("IsRepairMalformedUpdatesDisabled: %t\n", master.IsRepairMalformedUpdatesDisabled(k8sParams)) - log.Printf("IsServiceAccountLookupEnabled: %t\n", master.IsServiceAccountLookupEnabled(k8sParams)) - - log.Printf("IsKubeletHTTPSAbsentOrEnabled: %t\n", master.IsKubeletHTTPSAbsentOrEnabled(k8sParams)) - log.Printf("IsInsecureBindAddressAbsentOrLoopback: %t\n", master.IsInsecureBindAddressAbsentOrLoopback(k8sParams)) - log.Printf("IsSecurePortAbsentOrValid: %t\n", master.IsSecurePortAbsentOrValid(k8sParams)) - - log.Printf("IsAlwaysAdmitAdmissionControlPluginExcluded: %t\n", master.IsAlwaysAdmitAdmissionControlPluginExcluded(k8sParams)) - - log.Printf("IsAlwaysPullImagesAdmissionControlPluginIncluded: %t\n", master.IsAlwaysPullImagesAdmissionControlPluginIncluded(k8sParams)) - log.Printf("IsDenyEscalatingExecAdmissionControlPluginIncluded: %t\n", master.IsDenyEscalatingExecAdmissionControlPluginIncluded(k8sParams)) - log.Printf("IsSecurityContextDenyAdmissionControlPluginIncluded: %t\n", master.IsSecurityContextDenyAdmissionControlPluginIncluded(k8sParams)) - log.Printf("IsPodSecurityPolicyAdmissionControlPluginIncluded: %t\n", master.IsPodSecurityPolicyAdmissionControlPluginIncluded(k8sParams)) - log.Printf("IsServiceAccountAdmissionControlPluginIncluded: %t\n", master.IsServiceAccountAdmissionControlPluginIncluded(k8sParams)) - log.Printf("IsNodeRestrictionAdmissionControlPluginIncluded: %t\n", master.IsNodeRestrictionAdmissionControlPluginIncluded(k8sParams)) - log.Printf("IsEventRateLimitAdmissionControlPluginIncluded: %t\n", master.IsEventRateLimitAdmissionControlPluginIncluded(k8sParams)) - - log.Printf("IsNamespaceLifecycleAdmissionControlPluginNotExcluded: %t\n", master.IsNamespaceLifecycleAdmissionControlPluginNotExcluded(k8sParams)) - - log.Printf("IsAlwaysAllowAuthorizationModeExcluded: %t\n", master.IsAlwaysAllowAuthorizationModeExcluded(k8sParams)) - log.Printf("IsNodeAuthorizationModeIncluded: %t\n", master.IsNodeAuthorizationModeIncluded(k8sParams)) - - log.Printf("IsAuditLogPathSet: %t\n", master.IsAuditLogPathSet(k8sParams)) - log.Printf("IsAuditLogMaxAgeValid: %t\n", master.IsAuditLogMaxAgeValid(k8sParams)) - log.Printf("IsAuditLogMaxBackupValid: %t\n", master.IsAuditLogMaxBackupValid(k8sParams)) - log.Printf("IsAuditLogMaxSizeValid: %t\n", master.IsAuditLogMaxSizeValid(k8sParams)) - - log.Printf("IsRequestTimeoutValid: %t\n", master.IsRequestTimeoutValid(k8sParams)) - - log.Printf("IsKubeletCertificateAuthoritySet: %t\n", master.IsKubeletCertificateAuthoritySet(k8sParams)) - log.Printf("IsClientCertificateAuthoritySet: %t\n", master.IsClientCertificateAuthoritySet(k8sParams)) - log.Printf("IsEtcdCertificateAuthoritySet: %t\n", master.IsEtcdCertificateAuthoritySet(k8sParams)) - - log.Printf("IsServiceAccountKeySet: %t\n", master.IsServiceAccountKeySet(k8sParams)) - log.Printf("IsKubeletClientCertificateAndKeySet: %t\n", master.IsKubeletClientCertificateAndKeySet(k8sParams)) - log.Printf("IsEtcdCertificateAndKeySet: %t\n", master.IsEtcdCertificateAndKeySet(k8sParams)) - log.Printf("IsTLSCertificateAndKeySet: %t\n", master.IsTLSCertificateAndKeySet(k8sParams)) - - log.Printf("IsStrongCryptoCipherInUse: %t\n", master.IsStrongCryptoCipherInUse(k8sParams)) + master.Check(k8sParams) } diff --git a/test/security/k8s/src/check/validators/master/api.go b/test/security/k8s/src/check/validators/master/api.go deleted file mode 100644 index c2a99641e..000000000 --- a/test/security/k8s/src/check/validators/master/api.go +++ /dev/null @@ -1,391 +0,0 @@ -package master - -import ( - "strconv" - "strings" -) - -const ( - portDisabled = 0 - portLowest = 1 - portHighest = 65536 - - auditLogAge = 30 - auditLogBackups = 10 - auditLogSize = 100 - - strongCryptoCiphers = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM" + - "_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM" + - "_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM" + - "_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256" - - requestTimeout = 60 -) - -// IsBasicAuthFileAbsent validates there is no basic authentication file specified. -func IsBasicAuthFileAbsent(params []string) bool { - return isFlagAbsent("--basic-auth-file=", params) -} - -// IsTokenAuthFileAbsent validates there is no token based authentication file specified. -func IsTokenAuthFileAbsent(params []string) bool { - return isFlagAbsent("--token-auth-file=", params) -} - -// IsInsecureAllowAnyTokenAbsent validates insecure tokens are not accepted. -func IsInsecureAllowAnyTokenAbsent(params []string) bool { - return isFlagAbsent("--insecure-allow-any-token", params) -} - -// isFlagAbsent checks absence of selected flag in parameters. -func isFlagAbsent(flag string, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 0 { - return false - } - return true -} - -// IsAnonymousAuthDisabled validates there is single "--anonymous-auth" flag and it is set to "false". -func IsAnonymousAuthDisabled(params []string) bool { - return hasSingleFlagArgument("--anonymous-auth=", "false", params) -} - -// IsInsecurePortUnbound validates there is single "--insecure-port" flag and it is set to "0" (disabled). -func IsInsecurePortUnbound(params []string) bool { - return hasSingleFlagArgument("--insecure-port=", strconv.Itoa(portDisabled), params) -} - -// IsProfilingDisabled validates there is single "--profiling" flag and it is set to "false". -func IsProfilingDisabled(params []string) bool { - return hasSingleFlagArgument("--profiling=", "false", params) -} - -// IsRepairMalformedUpdatesDisabled validates there is single "--repair-malformed-updates" flag and it is set to "false". -func IsRepairMalformedUpdatesDisabled(params []string) bool { - return hasSingleFlagArgument("--repair-malformed-updates=", "false", params) -} - -// IsServiceAccountLookupEnabled validates there is single "--service-account-lookup" flag and it is set to "true". -func IsServiceAccountLookupEnabled(params []string) bool { - return hasSingleFlagArgument("--service-account-lookup=", "true", params) -} - -// IsStrongCryptoCipherInUse validates there is single "--tls-cipher-suites=" flag and it is set to strong crypto ciphers. -func IsStrongCryptoCipherInUse(params []string) bool { - return hasSingleFlagArgument("--tls-cipher-suites=", strongCryptoCiphers, params) -} - -// hasSingleFlagArgument checks whether selected flag was used once and has requested argument. -func hasSingleFlagArgument(flag string, argument string, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 1 { - return false - } - - _, value := splitKV(found[0], "=") - if value != argument { - return false - } - return true -} - -// filterFlags returns all occurrences of selected flag. -func filterFlags(strs []string, flag string) []string { - var filtered []string - for _, str := range strs { - if strings.HasPrefix(str, flag) { - filtered = append(filtered, str) - } - } - return filtered -} - -// splitKV splits key and value (after first occurrence of separator). -func splitKV(s, sep string) (string, string) { - ret := strings.SplitN(s, sep, 2) - return ret[0], ret[1] -} - -// IsKubeletHTTPSAbsentOrEnabled validates there is single "--kubelet-https" flag and it is set to "true". -func IsKubeletHTTPSAbsentOrEnabled(params []string) bool { - return isFlagAbsent("--kubelet-https=", params) || - hasSingleFlagArgument("--kubelet-https=", "true", params) -} - -// IsInsecureBindAddressAbsentOrLoopback validates there is no insecure bind address or it is loopback address. -func IsInsecureBindAddressAbsentOrLoopback(params []string) bool { - return isFlagAbsent("--insecure-bind-address=", params) || - hasSingleFlagArgument("--insecure-bind-address=", "127.0.0.1", params) -} - -// IsSecurePortAbsentOrValid validates there is no secure port set explicitly or it has legal value. -func IsSecurePortAbsentOrValid(params []string) bool { - return isFlagAbsent("--secure-port=", params) || - hasFlagValidPort("--secure-port=", params) -} - -// hasFlagValidPort checks whether selected flag has valid port as an argument in given command. -func hasFlagValidPort(flag string, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 1 { - return false - } - - _, value := splitKV(found[0], "=") - port, err := strconv.Atoi(value) // what about empty parameter? - if err != nil { - return false - } - if port < portLowest || port > portHighest { - return false - } - return true -} - -// IsAlwaysAdmitAdmissionControlPluginExcluded validates AlwaysAdmit is excluded from admission control plugins. -func IsAlwaysAdmitAdmissionControlPluginExcluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return !hasFlagArgumentIncluded("--enable-admission-plugins=", "AlwaysAdmit", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return !hasFlagArgumentIncluded("--admission-control=", "AlwaysAdmit", params) - } - return false -} - -// IsAlwaysPullImagesAdmissionControlPluginIncluded validates AlwaysPullImages is included in admission control plugins. -func IsAlwaysPullImagesAdmissionControlPluginIncluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return hasFlagArgumentIncluded("--enable-admission-plugins=", "AlwaysPullImages", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return hasFlagArgumentIncluded("--admission-control=", "AlwaysPullImages", params) - } - return false -} - -// IsDenyEscalatingExecAdmissionControlPluginIncluded validates DenyEscalatingExec is included in admission control plugins. -func IsDenyEscalatingExecAdmissionControlPluginIncluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return hasFlagArgumentIncluded("--enable-admission-plugins=", "DenyEscalatingExec", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return hasFlagArgumentIncluded("--admission-control=", "DenyEscalatingExec", params) - } - return false -} - -// IsSecurityContextDenyAdmissionControlPluginIncluded validates SecurityContextDeny is included in admission control plugins. -func IsSecurityContextDenyAdmissionControlPluginIncluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return hasFlagArgumentIncluded("--enable-admission-plugins=", "SecurityContextDeny", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return hasFlagArgumentIncluded("--admission-control=", "SecurityContextDeny", params) - } - return false -} - -// IsPodSecurityPolicyAdmissionControlPluginIncluded validates PodSecurityPolicy is included in admission control plugins. -func IsPodSecurityPolicyAdmissionControlPluginIncluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return hasFlagArgumentIncluded("--enable-admission-plugins=", "PodSecurityPolicy", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return hasFlagArgumentIncluded("--admission-control=", "PodSecurityPolicy", params) - } - return false -} - -// IsServiceAccountAdmissionControlPluginIncluded validates ServiceAccount is included in admission control plugins. -func IsServiceAccountAdmissionControlPluginIncluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return hasFlagArgumentIncluded("--enable-admission-plugins=", "ServiceAccount", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return hasFlagArgumentIncluded("--admission-control=", "ServiceAccount", params) - } - return false -} - -// IsNodeRestrictionAdmissionControlPluginIncluded validates NodeRestriction is included in admission control plugins. -func IsNodeRestrictionAdmissionControlPluginIncluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return hasFlagArgumentIncluded("--enable-admission-plugins=", "NodeRestriction", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return hasFlagArgumentIncluded("--admission-control=", "NodeRestriction", params) - } - return false -} - -// IsEventRateLimitAdmissionControlPluginIncluded validates EventRateLimit is included in admission control plugins. -func IsEventRateLimitAdmissionControlPluginIncluded(params []string) bool { - if isSingleFlagPresent("--enable-admission-plugins=", params) { - return hasFlagArgumentIncluded("--enable-admission-plugins=", "EventRateLimit", params) - } - if isSingleFlagPresent("--admission-control=", params) { - return hasFlagArgumentIncluded("--admission-control=", "EventRateLimit", params) - } - return false -} - -// IsNamespaceLifecycleAdmissionControlPluginNotExcluded validates NamespaceLifecycle is excluded from admission control plugins. -func IsNamespaceLifecycleAdmissionControlPluginNotExcluded(params []string) bool { - if isSingleFlagPresent("--disable-admission-plugins=", params) { - return !hasFlagArgumentIncluded("--disable-admission-plugins=", "NamespaceLifecycle", params) - } - return true -} - -// isSingleFlagPresent checks presence of selected flag and whether it was used once. -func isSingleFlagPresent(flag string, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 1 { - return false - } - return true -} - -// hasFlagArgumentIncluded checks whether selected flag includes requested argument. -func hasFlagArgumentIncluded(flag string, argument string, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 1 { - return false - } - - _, values := splitKV(found[0], "=") - for _, v := range strings.Split(values, ",") { - if v == argument { - return true - } - } - return false -} - -// IsAlwaysAllowAuthorizationModeExcluded validates AlwaysAllow is excluded from authorization modes. -func IsAlwaysAllowAuthorizationModeExcluded(params []string) bool { - return isSingleFlagPresent("--authorization-mode=", params) && - !hasFlagArgumentIncluded("--authorization-mode=", "AlwaysAllow", params) -} - -// IsNodeAuthorizationModeIncluded validates Node is included in authorization modes. -func IsNodeAuthorizationModeIncluded(params []string) bool { - return hasFlagArgumentIncluded("--authorization-mode=", "Node", params) -} - -// IsAuditLogPathSet validates there is single "--audit-log-path" flag and has non-empty argument. -func IsAuditLogPathSet(params []string) bool { - return hasSingleFlagNonemptyArgument("--audit-log-path=", params) -} - -// IsKubeletCertificateAuthoritySet validates there is single "--kubelet-certificate-authority" flag and has non-empty argument. -func IsKubeletCertificateAuthoritySet(params []string) bool { - return hasSingleFlagNonemptyArgument("--kubelet-certificate-authority", params) -} - -// IsClientCertificateAuthoritySet validates there is single "--client-ca-file" flag and has non-empty argument. -func IsClientCertificateAuthoritySet(params []string) bool { - return hasSingleFlagNonemptyArgument("--client-ca-file", params) -} - -// IsEtcdCertificateAuthoritySet validates there is single "--etcd-cafile" flag and has non-empty argument. -func IsEtcdCertificateAuthoritySet(params []string) bool { - return hasSingleFlagNonemptyArgument("--etcd-cafile", params) -} - -// IsServiceAccountKeySet validates there is single "--service-account-key-file" flag and has non-empty argument. -func IsServiceAccountKeySet(params []string) bool { - return hasSingleFlagNonemptyArgument("--service-account-key-file", params) -} - -// IsKubeletClientCertificateAndKeySet validates there are single "--kubelet-client-certificate" and "--kubelet-client-key" flags and have non-empty arguments. -func IsKubeletClientCertificateAndKeySet(params []string) bool { - return hasSingleFlagNonemptyArgument("--kubelet-client-certificate", params) && - hasSingleFlagNonemptyArgument("--kubelet-client-key", params) -} - -// IsEtcdCertificateAndKeySet validates there are single "--etcd-certfile" and "--etcd-keyfile" flags and have non-empty arguments. -func IsEtcdCertificateAndKeySet(params []string) bool { - return hasSingleFlagNonemptyArgument("--etcd-certfile", params) && - hasSingleFlagNonemptyArgument("--etcd-keyfile", params) -} - -// IsTLSCertificateAndKeySet validates there are single "--tls-cert-file" and "--tls-private-key-file" flags and have non-empty arguments. -func IsTLSCertificateAndKeySet(params []string) bool { - return hasSingleFlagNonemptyArgument("--tls-cert-file", params) && - hasSingleFlagNonemptyArgument("--tls-private-key-file", params) -} - -// hasSingleFlagNonemptyArgument checks whether selected flag was used once and has non-empty argument. -func hasSingleFlagNonemptyArgument(flag string, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 1 { - return false - } - - _, value := splitKV(found[0], "=") - if value == "" { - return false - } - return true -} - -// IsAuditLogMaxAgeValid validates audit log age is set and it has recommended value. -func IsAuditLogMaxAgeValid(params []string) bool { - return hasSingleFlagRecommendedNumericArgument("--audit-log-maxage", auditLogAge, params) -} - -// IsAuditLogMaxBackupValid validates audit log age is set and it has recommended value. -func IsAuditLogMaxBackupValid(params []string) bool { - return hasSingleFlagRecommendedNumericArgument("--audit-log-maxbackup", auditLogBackups, params) -} - -// IsAuditLogMaxSizeValid validates audit log age is set and it has recommended value. -func IsAuditLogMaxSizeValid(params []string) bool { - return hasSingleFlagRecommendedNumericArgument("--audit-log-maxsize", auditLogSize, params) -} - -// hasSingleFlagRecommendedNumericArgument checks whether selected flag was used once and has -// an argument that is greater or equal than the recommended value for given command. -func hasSingleFlagRecommendedNumericArgument(flag string, recommendation int, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 1 { - return false - } - - _, value := splitKV(found[0], "=") - arg, err := strconv.Atoi(value) // what about empty parameter? - if err != nil { - return false - } - if arg < recommendation { - return false - } - return true -} - -// IsRequestTimeoutValid validates request timeout is set and it has recommended value. -func IsRequestTimeoutValid(params []string) bool { - return isFlagAbsent("--request-timeout", params) || - hasSingleFlagValidTimeout("--request-timeout", requestTimeout, 2*requestTimeout, params) -} - -// hasSingleFlagValidTimeout checks whether selected flag has valid timeout as an argument in given command. -func hasSingleFlagValidTimeout(flag string, min int, max int, params []string) bool { - found := filterFlags(params, flag) - if len(found) != 1 { - return false - } - - _, value := splitKV(found[0], "=") - timeout, err := strconv.Atoi(value) // what about empty parameter? - if err != nil { - return false - } - if timeout < min || timeout > max { - return false - } - return true -} diff --git a/test/security/k8s/src/check/validators/master/api/api.go b/test/security/k8s/src/check/validators/master/api/api.go new file mode 100644 index 000000000..1ca920e1a --- /dev/null +++ b/test/security/k8s/src/check/validators/master/api/api.go @@ -0,0 +1,391 @@ +package api + +import ( + "strconv" + "strings" +) + +const ( + portDisabled = 0 + portLowest = 1 + portHighest = 65536 + + auditLogAge = 30 + auditLogBackups = 10 + auditLogSize = 100 + + strongCryptoCiphers = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM" + + "_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM" + + "_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM" + + "_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256" + + requestTimeout = 60 +) + +// IsBasicAuthFileAbsent validates there is no basic authentication file specified. +func IsBasicAuthFileAbsent(params []string) bool { + return isFlagAbsent("--basic-auth-file=", params) +} + +// IsTokenAuthFileAbsent validates there is no token based authentication file specified. +func IsTokenAuthFileAbsent(params []string) bool { + return isFlagAbsent("--token-auth-file=", params) +} + +// IsInsecureAllowAnyTokenAbsent validates insecure tokens are not accepted. +func IsInsecureAllowAnyTokenAbsent(params []string) bool { + return isFlagAbsent("--insecure-allow-any-token", params) +} + +// isFlagAbsent checks absence of selected flag in parameters. +func isFlagAbsent(flag string, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 0 { + return false + } + return true +} + +// IsAnonymousAuthDisabled validates there is single "--anonymous-auth" flag and it is set to "false". +func IsAnonymousAuthDisabled(params []string) bool { + return hasSingleFlagArgument("--anonymous-auth=", "false", params) +} + +// IsInsecurePortUnbound validates there is single "--insecure-port" flag and it is set to "0" (disabled). +func IsInsecurePortUnbound(params []string) bool { + return hasSingleFlagArgument("--insecure-port=", strconv.Itoa(portDisabled), params) +} + +// IsProfilingDisabled validates there is single "--profiling" flag and it is set to "false". +func IsProfilingDisabled(params []string) bool { + return hasSingleFlagArgument("--profiling=", "false", params) +} + +// IsRepairMalformedUpdatesDisabled validates there is single "--repair-malformed-updates" flag and it is set to "false". +func IsRepairMalformedUpdatesDisabled(params []string) bool { + return hasSingleFlagArgument("--repair-malformed-updates=", "false", params) +} + +// IsServiceAccountLookupEnabled validates there is single "--service-account-lookup" flag and it is set to "true". +func IsServiceAccountLookupEnabled(params []string) bool { + return hasSingleFlagArgument("--service-account-lookup=", "true", params) +} + +// IsStrongCryptoCipherInUse validates there is single "--tls-cipher-suites=" flag and it is set to strong crypto ciphers. +func IsStrongCryptoCipherInUse(params []string) bool { + return hasSingleFlagArgument("--tls-cipher-suites=", strongCryptoCiphers, params) +} + +// hasSingleFlagArgument checks whether selected flag was used once and has requested argument. +func hasSingleFlagArgument(flag string, argument string, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 1 { + return false + } + + _, value := splitKV(found[0], "=") + if value != argument { + return false + } + return true +} + +// filterFlags returns all occurrences of selected flag. +func filterFlags(strs []string, flag string) []string { + var filtered []string + for _, str := range strs { + if strings.HasPrefix(str, flag) { + filtered = append(filtered, str) + } + } + return filtered +} + +// splitKV splits key and value (after first occurrence of separator). +func splitKV(s, sep string) (string, string) { + ret := strings.SplitN(s, sep, 2) + return ret[0], ret[1] +} + +// IsKubeletHTTPSAbsentOrEnabled validates there is single "--kubelet-https" flag and it is set to "true". +func IsKubeletHTTPSAbsentOrEnabled(params []string) bool { + return isFlagAbsent("--kubelet-https=", params) || + hasSingleFlagArgument("--kubelet-https=", "true", params) +} + +// IsInsecureBindAddressAbsentOrLoopback validates there is no insecure bind address or it is loopback address. +func IsInsecureBindAddressAbsentOrLoopback(params []string) bool { + return isFlagAbsent("--insecure-bind-address=", params) || + hasSingleFlagArgument("--insecure-bind-address=", "127.0.0.1", params) +} + +// IsSecurePortAbsentOrValid validates there is no secure port set explicitly or it has legal value. +func IsSecurePortAbsentOrValid(params []string) bool { + return isFlagAbsent("--secure-port=", params) || + hasFlagValidPort("--secure-port=", params) +} + +// hasFlagValidPort checks whether selected flag has valid port as an argument in given command. +func hasFlagValidPort(flag string, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 1 { + return false + } + + _, value := splitKV(found[0], "=") + port, err := strconv.Atoi(value) // what about empty parameter? + if err != nil { + return false + } + if port < portLowest || port > portHighest { + return false + } + return true +} + +// IsAlwaysAdmitAdmissionControlPluginExcluded validates AlwaysAdmit is excluded from admission control plugins. +func IsAlwaysAdmitAdmissionControlPluginExcluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return !hasFlagArgumentIncluded("--enable-admission-plugins=", "AlwaysAdmit", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return !hasFlagArgumentIncluded("--admission-control=", "AlwaysAdmit", params) + } + return false +} + +// IsAlwaysPullImagesAdmissionControlPluginIncluded validates AlwaysPullImages is included in admission control plugins. +func IsAlwaysPullImagesAdmissionControlPluginIncluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return hasFlagArgumentIncluded("--enable-admission-plugins=", "AlwaysPullImages", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return hasFlagArgumentIncluded("--admission-control=", "AlwaysPullImages", params) + } + return false +} + +// IsDenyEscalatingExecAdmissionControlPluginIncluded validates DenyEscalatingExec is included in admission control plugins. +func IsDenyEscalatingExecAdmissionControlPluginIncluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return hasFlagArgumentIncluded("--enable-admission-plugins=", "DenyEscalatingExec", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return hasFlagArgumentIncluded("--admission-control=", "DenyEscalatingExec", params) + } + return false +} + +// IsSecurityContextDenyAdmissionControlPluginIncluded validates SecurityContextDeny is included in admission control plugins. +func IsSecurityContextDenyAdmissionControlPluginIncluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return hasFlagArgumentIncluded("--enable-admission-plugins=", "SecurityContextDeny", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return hasFlagArgumentIncluded("--admission-control=", "SecurityContextDeny", params) + } + return false +} + +// IsPodSecurityPolicyAdmissionControlPluginIncluded validates PodSecurityPolicy is included in admission control plugins. +func IsPodSecurityPolicyAdmissionControlPluginIncluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return hasFlagArgumentIncluded("--enable-admission-plugins=", "PodSecurityPolicy", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return hasFlagArgumentIncluded("--admission-control=", "PodSecurityPolicy", params) + } + return false +} + +// IsServiceAccountAdmissionControlPluginIncluded validates ServiceAccount is included in admission control plugins. +func IsServiceAccountAdmissionControlPluginIncluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return hasFlagArgumentIncluded("--enable-admission-plugins=", "ServiceAccount", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return hasFlagArgumentIncluded("--admission-control=", "ServiceAccount", params) + } + return false +} + +// IsNodeRestrictionAdmissionControlPluginIncluded validates NodeRestriction is included in admission control plugins. +func IsNodeRestrictionAdmissionControlPluginIncluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return hasFlagArgumentIncluded("--enable-admission-plugins=", "NodeRestriction", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return hasFlagArgumentIncluded("--admission-control=", "NodeRestriction", params) + } + return false +} + +// IsEventRateLimitAdmissionControlPluginIncluded validates EventRateLimit is included in admission control plugins. +func IsEventRateLimitAdmissionControlPluginIncluded(params []string) bool { + if isSingleFlagPresent("--enable-admission-plugins=", params) { + return hasFlagArgumentIncluded("--enable-admission-plugins=", "EventRateLimit", params) + } + if isSingleFlagPresent("--admission-control=", params) { + return hasFlagArgumentIncluded("--admission-control=", "EventRateLimit", params) + } + return false +} + +// IsNamespaceLifecycleAdmissionControlPluginNotExcluded validates NamespaceLifecycle is excluded from admission control plugins. +func IsNamespaceLifecycleAdmissionControlPluginNotExcluded(params []string) bool { + if isSingleFlagPresent("--disable-admission-plugins=", params) { + return !hasFlagArgumentIncluded("--disable-admission-plugins=", "NamespaceLifecycle", params) + } + return true +} + +// isSingleFlagPresent checks presence of selected flag and whether it was used once. +func isSingleFlagPresent(flag string, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 1 { + return false + } + return true +} + +// hasFlagArgumentIncluded checks whether selected flag includes requested argument. +func hasFlagArgumentIncluded(flag string, argument string, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 1 { + return false + } + + _, values := splitKV(found[0], "=") + for _, v := range strings.Split(values, ",") { + if v == argument { + return true + } + } + return false +} + +// IsAlwaysAllowAuthorizationModeExcluded validates AlwaysAllow is excluded from authorization modes. +func IsAlwaysAllowAuthorizationModeExcluded(params []string) bool { + return isSingleFlagPresent("--authorization-mode=", params) && + !hasFlagArgumentIncluded("--authorization-mode=", "AlwaysAllow", params) +} + +// IsNodeAuthorizationModeIncluded validates Node is included in authorization modes. +func IsNodeAuthorizationModeIncluded(params []string) bool { + return hasFlagArgumentIncluded("--authorization-mode=", "Node", params) +} + +// IsAuditLogPathSet validates there is single "--audit-log-path" flag and has non-empty argument. +func IsAuditLogPathSet(params []string) bool { + return hasSingleFlagNonemptyArgument("--audit-log-path=", params) +} + +// IsKubeletCertificateAuthoritySet validates there is single "--kubelet-certificate-authority" flag and has non-empty argument. +func IsKubeletCertificateAuthoritySet(params []string) bool { + return hasSingleFlagNonemptyArgument("--kubelet-certificate-authority", params) +} + +// IsClientCertificateAuthoritySet validates there is single "--client-ca-file" flag and has non-empty argument. +func IsClientCertificateAuthoritySet(params []string) bool { + return hasSingleFlagNonemptyArgument("--client-ca-file", params) +} + +// IsEtcdCertificateAuthoritySet validates there is single "--etcd-cafile" flag and has non-empty argument. +func IsEtcdCertificateAuthoritySet(params []string) bool { + return hasSingleFlagNonemptyArgument("--etcd-cafile", params) +} + +// IsServiceAccountKeySet validates there is single "--service-account-key-file" flag and has non-empty argument. +func IsServiceAccountKeySet(params []string) bool { + return hasSingleFlagNonemptyArgument("--service-account-key-file", params) +} + +// IsKubeletClientCertificateAndKeySet validates there are single "--kubelet-client-certificate" and "--kubelet-client-key" flags and have non-empty arguments. +func IsKubeletClientCertificateAndKeySet(params []string) bool { + return hasSingleFlagNonemptyArgument("--kubelet-client-certificate", params) && + hasSingleFlagNonemptyArgument("--kubelet-client-key", params) +} + +// IsEtcdCertificateAndKeySet validates there are single "--etcd-certfile" and "--etcd-keyfile" flags and have non-empty arguments. +func IsEtcdCertificateAndKeySet(params []string) bool { + return hasSingleFlagNonemptyArgument("--etcd-certfile", params) && + hasSingleFlagNonemptyArgument("--etcd-keyfile", params) +} + +// IsTLSCertificateAndKeySet validates there are single "--tls-cert-file" and "--tls-private-key-file" flags and have non-empty arguments. +func IsTLSCertificateAndKeySet(params []string) bool { + return hasSingleFlagNonemptyArgument("--tls-cert-file", params) && + hasSingleFlagNonemptyArgument("--tls-private-key-file", params) +} + +// hasSingleFlagNonemptyArgument checks whether selected flag was used once and has non-empty argument. +func hasSingleFlagNonemptyArgument(flag string, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 1 { + return false + } + + _, value := splitKV(found[0], "=") + if value == "" { + return false + } + return true +} + +// IsAuditLogMaxAgeValid validates audit log age is set and it has recommended value. +func IsAuditLogMaxAgeValid(params []string) bool { + return hasSingleFlagRecommendedNumericArgument("--audit-log-maxage", auditLogAge, params) +} + +// IsAuditLogMaxBackupValid validates audit log age is set and it has recommended value. +func IsAuditLogMaxBackupValid(params []string) bool { + return hasSingleFlagRecommendedNumericArgument("--audit-log-maxbackup", auditLogBackups, params) +} + +// IsAuditLogMaxSizeValid validates audit log age is set and it has recommended value. +func IsAuditLogMaxSizeValid(params []string) bool { + return hasSingleFlagRecommendedNumericArgument("--audit-log-maxsize", auditLogSize, params) +} + +// hasSingleFlagRecommendedNumericArgument checks whether selected flag was used once and has +// an argument that is greater or equal than the recommended value for given command. +func hasSingleFlagRecommendedNumericArgument(flag string, recommendation int, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 1 { + return false + } + + _, value := splitKV(found[0], "=") + arg, err := strconv.Atoi(value) // what about empty parameter? + if err != nil { + return false + } + if arg < recommendation { + return false + } + return true +} + +// IsRequestTimeoutValid validates request timeout is set and it has recommended value. +func IsRequestTimeoutValid(params []string) bool { + return isFlagAbsent("--request-timeout", params) || + hasSingleFlagValidTimeout("--request-timeout", requestTimeout, 2*requestTimeout, params) +} + +// hasSingleFlagValidTimeout checks whether selected flag has valid timeout as an argument in given command. +func hasSingleFlagValidTimeout(flag string, min int, max int, params []string) bool { + found := filterFlags(params, flag) + if len(found) != 1 { + return false + } + + _, value := splitKV(found[0], "=") + timeout, err := strconv.Atoi(value) // what about empty parameter? + if err != nil { + return false + } + if timeout < min || timeout > max { + return false + } + return true +} diff --git a/test/security/k8s/src/check/validators/master/api/api_suite_test.go b/test/security/k8s/src/check/validators/master/api/api_suite_test.go new file mode 100644 index 000000000..28066f963 --- /dev/null +++ b/test/security/k8s/src/check/validators/master/api/api_suite_test.go @@ -0,0 +1,13 @@ +package api_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestApi(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Api Suite") +} diff --git a/test/security/k8s/src/check/validators/master/api/api_test.go b/test/security/k8s/src/check/validators/master/api/api_test.go new file mode 100644 index 000000000..4ba5070a8 --- /dev/null +++ b/test/security/k8s/src/check/validators/master/api/api_test.go @@ -0,0 +1,518 @@ +package api_test + +import ( + . "check/validators/master/api" + + . "github.com/onsi/ginkgo/extensions/table" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Api", func() { + var ( + // kubeApiServerCISCompliant uses secure defaults or follows CIS guidelines explicitly. + kubeApiServerCISCompliant = []string{ + "--anonymous-auth=false", + "--insecure-port=0", + "--profiling=false", + "--repair-malformed-updates=false", + "--service-account-lookup=true", + "--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount," + + "TaintNodesByCondition,Priority,DefaultTolerationSeconds,DefaultStorageClass," + + "PersistentVolumeClaimResize,MutatingAdmissionWebhook,ValidatingAdmissionWebhook," + + "ResourceQuota,AlwaysPullImages,DenyEscalatingExec,SecurityContextDeny," + + "PodSecurityPolicy,NodeRestriction,EventRateLimit", + "--authorization-mode=Node,RBAC", + "--audit-log-path=/var/log/apiserver/audit.log", + "--audit-log-maxage=30", + "--audit-log-maxbackup=10", + "--audit-log-maxsize=100", + "--kubelet-certificate-authority=TrustedCA", + "--client-ca-file=/etc/kubernetes/ssl/ca.pem", + "--etcd-cafile=/etc/kubernetes/etcd/ca.pem", + "--service-account-key-file=/etc/kubernetes/ssl/kube-service-account-token-key.pem", + "--kubelet-client-certificate=/etc/kubernetes/ssl/cert.pem", + "--kubelet-client-key=/etc/kubernetes/ssl/key.pem", + "--etcd-certfile=/etc/kubernetes/etcd/cert.pem", + "--etcd-keyfile=/etc/kubernetes/etcd/key.pem", + "--tls-cert-file=/etc/kubernetes/ssl/cert.pem", + "--tls-private-key-file=/etc/kubernetes/ssl/key.pem", + "--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," + + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305," + + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305," + + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384," + + "TLS_RSA_WITH_AES_128_GCM_SHA256", + } + + // kubeApiServerCasablanca was obtained from virtual environment for testing + // (introduced in Change-Id: I57f9f3caac0e8b391e9ed480f6bebba98e006882). + kubeApiServerCasablanca = []string{ + "--storage-backend=etcd2", + "--storage-media-type=application/json", + "--service-cluster-ip-range=10.43.0.0/16", + "--etcd-servers=https://etcd.kubernetes.rancher.internal:2379", + "--insecure-bind-address=0.0.0.0", + "--insecure-port=0", + "--cloud-provider=rancher", + "--allow-privileged=true", + "--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount," + + "PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,ResourceQuota", + "--client-ca-file=/etc/kubernetes/ssl/ca.pem", + "--tls-cert-file=/etc/kubernetes/ssl/cert.pem", + "--tls-private-key-file=/etc/kubernetes/ssl/key.pem", + "--kubelet-client-certificate=/etc/kubernetes/ssl/cert.pem", + "--kubelet-client-key=/etc/kubernetes/ssl/key.pem", + "--runtime-config=batch/v2alpha1", + "--anonymous-auth=false", + "--authentication-token-webhook-config-file=/etc/kubernetes/authconfig", + "--runtime-config=authentication.k8s.io/v1beta1=true", + "--external-hostname=kubernetes.kubernetes.rancher.internal", + "--etcd-cafile=/etc/kubernetes/etcd/ca.pem", + "--etcd-certfile=/etc/kubernetes/etcd/cert.pem", + "--etcd-keyfile=/etc/kubernetes/etcd/key.pem", + "--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," + + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305," + + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," + + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + } + + // kubeApiServerCasablanca was obtained from virtual environment for testing + // (introduced in Change-Id: I54ada5fade3b984dedd1715f20579e3ce901faa3). + kubeApiServerDublin = []string{ + "--requestheader-group-headers=X-Remote-Group", + "--proxy-client-cert-file=/etc/kubernetes/ssl/kube-apiserver-proxy-client.pem", + "--bind-address=0.0.0.0", + "--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," + + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305," + + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," + + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + "--cloud-provider=", + "--etcd-cafile=/etc/kubernetes/ssl/kube-ca.pem", + "--etcd-servers=https://172.17.0.100:2379", + "--tls-cert-file=/etc/kubernetes/ssl/kube-apiserver.pem", + "--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount," + + "DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook," + + "ValidatingAdmissionWebhook,ResourceQuota,NodeRestriction,PersistentVolumeLabel", + "--insecure-port=0", + "--secure-port=6443", + "--storage-backend=etcd3", + "--kubelet-client-key=/etc/kubernetes/ssl/kube-apiserver-key.pem", + "--requestheader-client-ca-file=/etc/kubernetes/ssl/kube-apiserver-requestheader-ca.pem", + "--service-account-key-file=/etc/kubernetes/ssl/kube-service-account-token-key.pem", + "--service-node-port-range=30000-32767", + "--tls-private-key-file=/etc/kubernetes/ssl/kube-apiserver-key.pem", + "--requestheader-username-headers=X-Remote-User", + "--repair-malformed-updates=false", + "--kubelet-client-certificate=/etc/kubernetes/ssl/kube-apiserver.pem", + "--service-cluster-ip-range=10.43.0.0/16", + "--advertise-address=172.17.0.100", + "--profiling=false", + "--requestheader-extra-headers-prefix=X-Remote-Extra-", + "--etcd-certfile=/etc/kubernetes/ssl/kube-node.pem", + "--anonymous-auth=false", + "--etcd-keyfile=/etc/kubernetes/ssl/kube-node-key.pem", + "--etcd-prefix=/registry", + "--client-ca-file=/etc/kubernetes/ssl/kube-ca.pem", + "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", + "--requestheader-allowed-names=kube-apiserver-proxy-client", + "--service-account-lookup=true", + "--proxy-client-key-file=/etc/kubernetes/ssl/kube-apiserver-proxy-client-key.pem", + "--authorization-mode=Node,RBAC", + "--allow-privileged=true", + } + ) + + Describe("Boolean flags", func() { + DescribeTable("Accepting any token", + func(params []string, expected bool) { + Expect(IsInsecureAllowAnyTokenAbsent(params)).To(Equal(expected)) + }, + Entry("Is not absent on insecure cluster", []string{"--insecure-allow-any-token"}, false), + Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Anonymous requests", + func(params []string, expected bool) { + Expect(IsAnonymousAuthDisabled(params)).To(Equal(expected)) + }, + Entry("Is not set on insecure cluster", []string{}, false), + Entry("Should be set to false on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be set to false on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be set to false on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Profiling", + func(params []string, expected bool) { + Expect(IsProfilingDisabled(params)).To(Equal(expected)) + }, + Entry("Is not set on insecure cluster", []string{}, false), + Entry("Is explicitly enabled on insecure cluster", []string{"--profiling=true"}, false), + Entry("Is not set on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should be set to false on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be set to false on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("HTTPS for kubelet", + func(params []string, expected bool) { + Expect(IsKubeletHTTPSAbsentOrEnabled(params)).To(Equal(expected)) + }, + Entry("Is explicitly disabled on insecure cluster", []string{"--kubelet-https=false"}, false), + Entry("Should be absent or set to true on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent or set to true on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be absent or set to true on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Repairing malformed updates", + func(params []string, expected bool) { + Expect(IsRepairMalformedUpdatesDisabled(params)).To(Equal(expected)) + }, + Entry("Is not set on insecure cluster", []string{}, false), + Entry("Is explicitly enabled on insecure cluster", []string{"--repair-malformed-updates=true"}, false), + Entry("Is not set on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should be set to false on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be set to false on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Service account lookup", + func(params []string, expected bool) { + Expect(IsServiceAccountLookupEnabled(params)).To(Equal(expected)) + }, + Entry("Is not set on insecure cluster", []string{}, false), + Entry("Is explicitly disabled on insecure cluster", []string{"--service-account-lookup=false"}, false), + Entry("Is not set on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should be set to true on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be set to true on Dublin cluster", kubeApiServerDublin, true), + ) + }) + + Describe("File path flags", func() { + DescribeTable("Basic authentication file", + func(params []string, expected bool) { + Expect(IsBasicAuthFileAbsent(params)).To(Equal(expected)) + }, + Entry("Is not absent on insecure cluster", []string{"--basic-auth-file=/path/to/file"}, false), + Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Token authentication file", + func(params []string, expected bool) { + Expect(IsTokenAuthFileAbsent(params)).To(Equal(expected)) + }, + Entry("Is not absent on insecure cluster", []string{"--token-auth-file=/path/to/file"}, false), + Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Audit log path", + func(params []string, expected bool) { + Expect(IsAuditLogPathSet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--audit-log-path="}, false), + Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("Kubelet certificate authority", + func(params []string, expected bool) { + Expect(IsKubeletCertificateAuthoritySet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--kubelet-certificate-authority="}, false), + Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("Client certificate authority", + func(params []string, expected bool) { + Expect(IsClientCertificateAuthoritySet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--client-ca-file="}, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Etcd certificate authority", + func(params []string, expected bool) { + Expect(IsEtcdCertificateAuthoritySet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"-etcd-cafile="}, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Service account key", + func(params []string, expected bool) { + Expect(IsServiceAccountKeySet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--service-account-key-file="}, false), + Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Kubelet client certificate and key", + func(params []string, expected bool) { + Expect(IsKubeletClientCertificateAndKeySet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--kubelet-client-certificate= --kubelet-client-key="}, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Etcd certificate and key", + func(params []string, expected bool) { + Expect(IsEtcdCertificateAndKeySet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--etcd-certfile= --etcd-keyfile="}, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("TLS certificate and key", + func(params []string, expected bool) { + Expect(IsTLSCertificateAndKeySet(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--tls-cert-file= --tls-private-key-file="}, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + }) + + Describe("Address and port flags", func() { + DescribeTable("Bind address", + func(params []string, expected bool) { + Expect(IsInsecureBindAddressAbsentOrLoopback(params)).To(Equal(expected)) + }, + Entry("Is not absent on insecure cluster", []string{"--insecure-bind-address=1.2.3.4"}, false), + Entry("Is not absent nor set to loopback on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should be absent or set to loopback on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent or set to loopback on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Bind port", + func(params []string, expected bool) { + Expect(IsInsecurePortUnbound(params)).To(Equal(expected)) + }, + Entry("Is not set on insecure cluster", []string{}, false), + Entry("Is explicitly enabled on insecure cluster", []string{"--insecure-port=1234"}, false), + Entry("Should be set to 0 on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be set to 0 on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be set to 0 on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Secure bind port", + func(params []string, expected bool) { + Expect(IsSecurePortAbsentOrValid(params)).To(Equal(expected)) + }, + Entry("Is explicitly disabled on insecure cluster", []string{"--secure-port=0"}, false), + Entry("Should be absent or set to valid port on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent or set to valid port on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be absent or set to valid port on Dublin cluster", kubeApiServerDublin, true), + ) + }) + + Describe("Numeric flags", func() { + DescribeTable("Audit log age", + func(params []string, expected bool) { + Expect(IsAuditLogMaxAgeValid(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--audit-log-maxage="}, false), + Entry("Is insufficient on insecure cluster", []string{"--audit-log-maxage=5"}, false), + Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be set appropriately on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("Audit log backups", + func(params []string, expected bool) { + Expect(IsAuditLogMaxBackupValid(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--audit-log-maxbackup="}, false), + Entry("Is insufficient on insecure cluster", []string{"--audit-log-maxbackup=2"}, false), + Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be set appropriately on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("Audit log size", + func(params []string, expected bool) { + Expect(IsAuditLogMaxSizeValid(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--audit-log-maxsize="}, false), + Entry("Is insufficient on insecure cluster", []string{"--audit-log-maxsize=5"}, false), + Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be set appropriately on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("Request timeout", + func(params []string, expected bool) { + Expect(IsRequestTimeoutValid(params)).To(Equal(expected)) + }, + Entry("Is empty on insecure cluster", []string{"--request-timeout="}, false), + Entry("Is too high on insecure cluster", []string{"--request-timeout=600"}, false), + Entry("Should be set only if needed on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be set only if needed on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be set only if needed on Dublin cluster", kubeApiServerDublin, true), + ) + }) + + Describe("Argument list flags", func() { + DescribeTable("AlwaysAdmit admission control plugin", + func(params []string, expected bool) { + Expect(IsAlwaysAdmitAdmissionControlPluginExcluded(params)).To(Equal(expected)) + }, + Entry("Is not absent on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar,AlwaysAdmit,Baz,Quuz"}, false), + Entry("Is not absent on insecure deprecated cluster", []string{"--admission-control=Foo,Bar,AlwaysAdmit,Baz,Quuz"}, false), + Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("AlwaysPullImages admission control plugin", + func(params []string, expected bool) { + Expect(IsAlwaysPullImagesAdmissionControlPluginIncluded(params)).To(Equal(expected)) + }, + Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), + Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), + Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("DenyEscalatingExec admission control plugin", + func(params []string, expected bool) { + Expect(IsDenyEscalatingExecAdmissionControlPluginIncluded(params)).To(Equal(expected)) + }, + Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), + Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), + Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("SecurityContextDeny admission control plugin", + func(params []string, expected bool) { + Expect(IsSecurityContextDenyAdmissionControlPluginIncluded(params)).To(Equal(expected)) + }, + Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), + Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), + Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("PodSecurityPolicy admission control plugin", + func(params []string, expected bool) { + Expect(IsPodSecurityPolicyAdmissionControlPluginIncluded(params)).To(Equal(expected)) + }, + Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), + Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), + Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("ServiceAccount admission control plugin", + func(params []string, expected bool) { + Expect(IsServiceAccountAdmissionControlPluginIncluded(params)).To(Equal(expected)) + }, + Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), + Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("NodeRestriction admission control plugin", + func(params []string, expected bool) { + Expect(IsNodeRestrictionAdmissionControlPluginIncluded(params)).To(Equal(expected)) + }, + Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), + Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), + Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("EventRateLimit admission control plugin", + func(params []string, expected bool) { + Expect(IsEventRateLimitAdmissionControlPluginIncluded(params)).To(Equal(expected)) + }, + Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), + Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), + Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + + DescribeTable("NamespaceLifecycle admission control plugin", + func(params []string, expected bool) { + Expect(IsNamespaceLifecycleAdmissionControlPluginNotExcluded(params)).To(Equal(expected)) + }, + Entry("Is explicitly disabled on insecure cluster", []string{"--disable-admission-plugins=Foo,Bar,NamespaceLifecycle,Baz,Quuz"}, false), + Entry("Should not be disabled on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should not be disabled on Casablanca cluster", kubeApiServerCasablanca, true), + Entry("Should not be disabled on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("AlwaysAllow authorization mode", + func(params []string, expected bool) { + Expect(IsAlwaysAllowAuthorizationModeExcluded(params)).To(Equal(expected)) + }, + Entry("Is not explicitly disabled on insecure cluster", []string{}, false), + Entry("Is not absent on insecure cluster", []string{"--authorization-mode=Foo,Bar,AlwaysAllow,Baz,Quuz"}, false), + Entry("Is not explicitly disabled on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), + ) + + DescribeTable("Node authorization mode", + func(params []string, expected bool) { + Expect(IsNodeAuthorizationModeIncluded(params)).To(Equal(expected)) + }, + Entry("Is not explicitly enabled on insecure cluster", []string{}, false), + Entry("Is not present on insecure cluster", []string{"--authorization-mode=Foo,Bar"}, false), + Entry("Is not explicitly enabled on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Should present on CIS-compliant cluster", kubeApiServerCISCompliant, true), + Entry("Should present on Dublin cluster", kubeApiServerDublin, true), + ) + }) + + Describe("Flags requiring strict equality", func() { + DescribeTable("Strong Cryptographic Ciphers", + func(params []string, expected bool) { + Expect(IsStrongCryptoCipherInUse(params)).To(Equal(expected)) + }, + Entry("Is absent on insecure cluster", []string{}, false), + Entry("Is empty on insecure cluster", []string{"--tls-cipher-suites="}, false), + Entry("Is incomplete on insecure cluster", []string{"--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, false), + Entry("Is incomplete on Casablanca cluster", kubeApiServerCasablanca, false), + Entry("Is incomplete on Dublin cluster", kubeApiServerDublin, false), + Entry("Should be complete on CIS-compliant cluster", kubeApiServerCISCompliant, true), + ) + }) +}) diff --git a/test/security/k8s/src/check/validators/master/api_test.go b/test/security/k8s/src/check/validators/master/api_test.go deleted file mode 100644 index 0b2021538..000000000 --- a/test/security/k8s/src/check/validators/master/api_test.go +++ /dev/null @@ -1,518 +0,0 @@ -package master_test - -import ( - . "check/validators/master" - - . "github.com/onsi/ginkgo/extensions/table" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Api", func() { - var ( - // kubeApiServerCISCompliant uses secure defaults or follows CIS guidelines explicitly. - kubeApiServerCISCompliant = []string{ - "--anonymous-auth=false", - "--insecure-port=0", - "--profiling=false", - "--repair-malformed-updates=false", - "--service-account-lookup=true", - "--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount," + - "TaintNodesByCondition,Priority,DefaultTolerationSeconds,DefaultStorageClass," + - "PersistentVolumeClaimResize,MutatingAdmissionWebhook,ValidatingAdmissionWebhook," + - "ResourceQuota,AlwaysPullImages,DenyEscalatingExec,SecurityContextDeny," + - "PodSecurityPolicy,NodeRestriction,EventRateLimit", - "--authorization-mode=Node,RBAC", - "--audit-log-path=/var/log/apiserver/audit.log", - "--audit-log-maxage=30", - "--audit-log-maxbackup=10", - "--audit-log-maxsize=100", - "--kubelet-certificate-authority=TrustedCA", - "--client-ca-file=/etc/kubernetes/ssl/ca.pem", - "--etcd-cafile=/etc/kubernetes/etcd/ca.pem", - "--service-account-key-file=/etc/kubernetes/ssl/kube-service-account-token-key.pem", - "--kubelet-client-certificate=/etc/kubernetes/ssl/cert.pem", - "--kubelet-client-key=/etc/kubernetes/ssl/key.pem", - "--etcd-certfile=/etc/kubernetes/etcd/cert.pem", - "--etcd-keyfile=/etc/kubernetes/etcd/key.pem", - "--tls-cert-file=/etc/kubernetes/ssl/cert.pem", - "--tls-private-key-file=/etc/kubernetes/ssl/key.pem", - "--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305," + - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305," + - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384," + - "TLS_RSA_WITH_AES_128_GCM_SHA256", - } - - // kubeApiServerCasablanca was obtained from virtual environment for testing - // (introduced in Change-Id: I57f9f3caac0e8b391e9ed480f6bebba98e006882). - kubeApiServerCasablanca = []string{ - "--storage-backend=etcd2", - "--storage-media-type=application/json", - "--service-cluster-ip-range=10.43.0.0/16", - "--etcd-servers=https://etcd.kubernetes.rancher.internal:2379", - "--insecure-bind-address=0.0.0.0", - "--insecure-port=0", - "--cloud-provider=rancher", - "--allow-privileged=true", - "--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount," + - "PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,ResourceQuota", - "--client-ca-file=/etc/kubernetes/ssl/ca.pem", - "--tls-cert-file=/etc/kubernetes/ssl/cert.pem", - "--tls-private-key-file=/etc/kubernetes/ssl/key.pem", - "--kubelet-client-certificate=/etc/kubernetes/ssl/cert.pem", - "--kubelet-client-key=/etc/kubernetes/ssl/key.pem", - "--runtime-config=batch/v2alpha1", - "--anonymous-auth=false", - "--authentication-token-webhook-config-file=/etc/kubernetes/authconfig", - "--runtime-config=authentication.k8s.io/v1beta1=true", - "--external-hostname=kubernetes.kubernetes.rancher.internal", - "--etcd-cafile=/etc/kubernetes/etcd/ca.pem", - "--etcd-certfile=/etc/kubernetes/etcd/cert.pem", - "--etcd-keyfile=/etc/kubernetes/etcd/key.pem", - "--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," + - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305," + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," + - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", - } - - // kubeApiServerCasablanca was obtained from virtual environment for testing - // (introduced in Change-Id: I54ada5fade3b984dedd1715f20579e3ce901faa3). - kubeApiServerDublin = []string{ - "--requestheader-group-headers=X-Remote-Group", - "--proxy-client-cert-file=/etc/kubernetes/ssl/kube-apiserver-proxy-client.pem", - "--bind-address=0.0.0.0", - "--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," + - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305," + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," + - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", - "--cloud-provider=", - "--etcd-cafile=/etc/kubernetes/ssl/kube-ca.pem", - "--etcd-servers=https://172.17.0.100:2379", - "--tls-cert-file=/etc/kubernetes/ssl/kube-apiserver.pem", - "--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount," + - "DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook," + - "ValidatingAdmissionWebhook,ResourceQuota,NodeRestriction,PersistentVolumeLabel", - "--insecure-port=0", - "--secure-port=6443", - "--storage-backend=etcd3", - "--kubelet-client-key=/etc/kubernetes/ssl/kube-apiserver-key.pem", - "--requestheader-client-ca-file=/etc/kubernetes/ssl/kube-apiserver-requestheader-ca.pem", - "--service-account-key-file=/etc/kubernetes/ssl/kube-service-account-token-key.pem", - "--service-node-port-range=30000-32767", - "--tls-private-key-file=/etc/kubernetes/ssl/kube-apiserver-key.pem", - "--requestheader-username-headers=X-Remote-User", - "--repair-malformed-updates=false", - "--kubelet-client-certificate=/etc/kubernetes/ssl/kube-apiserver.pem", - "--service-cluster-ip-range=10.43.0.0/16", - "--advertise-address=172.17.0.100", - "--profiling=false", - "--requestheader-extra-headers-prefix=X-Remote-Extra-", - "--etcd-certfile=/etc/kubernetes/ssl/kube-node.pem", - "--anonymous-auth=false", - "--etcd-keyfile=/etc/kubernetes/ssl/kube-node-key.pem", - "--etcd-prefix=/registry", - "--client-ca-file=/etc/kubernetes/ssl/kube-ca.pem", - "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", - "--requestheader-allowed-names=kube-apiserver-proxy-client", - "--service-account-lookup=true", - "--proxy-client-key-file=/etc/kubernetes/ssl/kube-apiserver-proxy-client-key.pem", - "--authorization-mode=Node,RBAC", - "--allow-privileged=true", - } - ) - - Describe("Boolean flags", func() { - DescribeTable("Accepting any token", - func(params []string, expected bool) { - Expect(IsInsecureAllowAnyTokenAbsent(params)).To(Equal(expected)) - }, - Entry("Is not absent on insecure cluster", []string{"--insecure-allow-any-token"}, false), - Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Anonymous requests", - func(params []string, expected bool) { - Expect(IsAnonymousAuthDisabled(params)).To(Equal(expected)) - }, - Entry("Is not set on insecure cluster", []string{}, false), - Entry("Should be set to false on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be set to false on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be set to false on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Profiling", - func(params []string, expected bool) { - Expect(IsProfilingDisabled(params)).To(Equal(expected)) - }, - Entry("Is not set on insecure cluster", []string{}, false), - Entry("Is explicitly enabled on insecure cluster", []string{"--profiling=true"}, false), - Entry("Is not set on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should be set to false on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be set to false on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("HTTPS for kubelet", - func(params []string, expected bool) { - Expect(IsKubeletHTTPSAbsentOrEnabled(params)).To(Equal(expected)) - }, - Entry("Is explicitly disabled on insecure cluster", []string{"--kubelet-https=false"}, false), - Entry("Should be absent or set to true on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent or set to true on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be absent or set to true on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Repairing malformed updates", - func(params []string, expected bool) { - Expect(IsRepairMalformedUpdatesDisabled(params)).To(Equal(expected)) - }, - Entry("Is not set on insecure cluster", []string{}, false), - Entry("Is explicitly enabled on insecure cluster", []string{"--repair-malformed-updates=true"}, false), - Entry("Is not set on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should be set to false on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be set to false on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Service account lookup", - func(params []string, expected bool) { - Expect(IsServiceAccountLookupEnabled(params)).To(Equal(expected)) - }, - Entry("Is not set on insecure cluster", []string{}, false), - Entry("Is explicitly disabled on insecure cluster", []string{"--service-account-lookup=false"}, false), - Entry("Is not set on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should be set to true on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be set to true on Dublin cluster", kubeApiServerDublin, true), - ) - }) - - Describe("File path flags", func() { - DescribeTable("Basic authentication file", - func(params []string, expected bool) { - Expect(IsBasicAuthFileAbsent(params)).To(Equal(expected)) - }, - Entry("Is not absent on insecure cluster", []string{"--basic-auth-file=/path/to/file"}, false), - Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Token authentication file", - func(params []string, expected bool) { - Expect(IsTokenAuthFileAbsent(params)).To(Equal(expected)) - }, - Entry("Is not absent on insecure cluster", []string{"--token-auth-file=/path/to/file"}, false), - Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Audit log path", - func(params []string, expected bool) { - Expect(IsAuditLogPathSet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--audit-log-path="}, false), - Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("Kubelet certificate authority", - func(params []string, expected bool) { - Expect(IsKubeletCertificateAuthoritySet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--kubelet-certificate-authority="}, false), - Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("Client certificate authority", - func(params []string, expected bool) { - Expect(IsClientCertificateAuthoritySet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--client-ca-file="}, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Etcd certificate authority", - func(params []string, expected bool) { - Expect(IsEtcdCertificateAuthoritySet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"-etcd-cafile="}, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Service account key", - func(params []string, expected bool) { - Expect(IsServiceAccountKeySet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--service-account-key-file="}, false), - Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Kubelet client certificate and key", - func(params []string, expected bool) { - Expect(IsKubeletClientCertificateAndKeySet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--kubelet-client-certificate= --kubelet-client-key="}, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Etcd certificate and key", - func(params []string, expected bool) { - Expect(IsEtcdCertificateAndKeySet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--etcd-certfile= --etcd-keyfile="}, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("TLS certificate and key", - func(params []string, expected bool) { - Expect(IsTLSCertificateAndKeySet(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--tls-cert-file= --tls-private-key-file="}, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - }) - - Describe("Address and port flags", func() { - DescribeTable("Bind address", - func(params []string, expected bool) { - Expect(IsInsecureBindAddressAbsentOrLoopback(params)).To(Equal(expected)) - }, - Entry("Is not absent on insecure cluster", []string{"--insecure-bind-address=1.2.3.4"}, false), - Entry("Is not absent nor set to loopback on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should be absent or set to loopback on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent or set to loopback on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Bind port", - func(params []string, expected bool) { - Expect(IsInsecurePortUnbound(params)).To(Equal(expected)) - }, - Entry("Is not set on insecure cluster", []string{}, false), - Entry("Is explicitly enabled on insecure cluster", []string{"--insecure-port=1234"}, false), - Entry("Should be set to 0 on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be set to 0 on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be set to 0 on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Secure bind port", - func(params []string, expected bool) { - Expect(IsSecurePortAbsentOrValid(params)).To(Equal(expected)) - }, - Entry("Is explicitly disabled on insecure cluster", []string{"--secure-port=0"}, false), - Entry("Should be absent or set to valid port on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent or set to valid port on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be absent or set to valid port on Dublin cluster", kubeApiServerDublin, true), - ) - }) - - Describe("Numeric flags", func() { - DescribeTable("Audit log age", - func(params []string, expected bool) { - Expect(IsAuditLogMaxAgeValid(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--audit-log-maxage="}, false), - Entry("Is insufficient on insecure cluster", []string{"--audit-log-maxage=5"}, false), - Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be set appropriately on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("Audit log backups", - func(params []string, expected bool) { - Expect(IsAuditLogMaxBackupValid(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--audit-log-maxbackup="}, false), - Entry("Is insufficient on insecure cluster", []string{"--audit-log-maxbackup=2"}, false), - Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be set appropriately on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("Audit log size", - func(params []string, expected bool) { - Expect(IsAuditLogMaxSizeValid(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--audit-log-maxsize="}, false), - Entry("Is insufficient on insecure cluster", []string{"--audit-log-maxsize=5"}, false), - Entry("Is absent on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is absent on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be set appropriately on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("Request timeout", - func(params []string, expected bool) { - Expect(IsRequestTimeoutValid(params)).To(Equal(expected)) - }, - Entry("Is empty on insecure cluster", []string{"--request-timeout="}, false), - Entry("Is too high on insecure cluster", []string{"--request-timeout=600"}, false), - Entry("Should be set only if needed on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be set only if needed on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be set only if needed on Dublin cluster", kubeApiServerDublin, true), - ) - }) - - Describe("Argument list flags", func() { - DescribeTable("AlwaysAdmit admission control plugin", - func(params []string, expected bool) { - Expect(IsAlwaysAdmitAdmissionControlPluginExcluded(params)).To(Equal(expected)) - }, - Entry("Is not absent on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar,AlwaysAdmit,Baz,Quuz"}, false), - Entry("Is not absent on insecure deprecated cluster", []string{"--admission-control=Foo,Bar,AlwaysAdmit,Baz,Quuz"}, false), - Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("AlwaysPullImages admission control plugin", - func(params []string, expected bool) { - Expect(IsAlwaysPullImagesAdmissionControlPluginIncluded(params)).To(Equal(expected)) - }, - Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), - Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), - Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("DenyEscalatingExec admission control plugin", - func(params []string, expected bool) { - Expect(IsDenyEscalatingExecAdmissionControlPluginIncluded(params)).To(Equal(expected)) - }, - Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), - Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), - Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("SecurityContextDeny admission control plugin", - func(params []string, expected bool) { - Expect(IsSecurityContextDenyAdmissionControlPluginIncluded(params)).To(Equal(expected)) - }, - Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), - Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), - Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("PodSecurityPolicy admission control plugin", - func(params []string, expected bool) { - Expect(IsPodSecurityPolicyAdmissionControlPluginIncluded(params)).To(Equal(expected)) - }, - Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), - Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), - Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("ServiceAccount admission control plugin", - func(params []string, expected bool) { - Expect(IsServiceAccountAdmissionControlPluginIncluded(params)).To(Equal(expected)) - }, - Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), - Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("NodeRestriction admission control plugin", - func(params []string, expected bool) { - Expect(IsNodeRestrictionAdmissionControlPluginIncluded(params)).To(Equal(expected)) - }, - Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), - Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), - Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be present on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("EventRateLimit admission control plugin", - func(params []string, expected bool) { - Expect(IsEventRateLimitAdmissionControlPluginIncluded(params)).To(Equal(expected)) - }, - Entry("Is not present on insecure cluster", []string{"--enable-admission-plugins=Foo,Bar"}, false), - Entry("Is not present on insecure deprecated cluster", []string{"--admission-control=Foo,Bar"}, false), - Entry("Is not present on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is not present on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - - DescribeTable("NamespaceLifecycle admission control plugin", - func(params []string, expected bool) { - Expect(IsNamespaceLifecycleAdmissionControlPluginNotExcluded(params)).To(Equal(expected)) - }, - Entry("Is explicitly disabled on insecure cluster", []string{"--disable-admission-plugins=Foo,Bar,NamespaceLifecycle,Baz,Quuz"}, false), - Entry("Should not be disabled on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should not be disabled on Casablanca cluster", kubeApiServerCasablanca, true), - Entry("Should not be disabled on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("AlwaysAllow authorization mode", - func(params []string, expected bool) { - Expect(IsAlwaysAllowAuthorizationModeExcluded(params)).To(Equal(expected)) - }, - Entry("Is not explicitly disabled on insecure cluster", []string{}, false), - Entry("Is not absent on insecure cluster", []string{"--authorization-mode=Foo,Bar,AlwaysAllow,Baz,Quuz"}, false), - Entry("Is not explicitly disabled on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should be absent on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should be absent on Dublin cluster", kubeApiServerDublin, true), - ) - - DescribeTable("Node authorization mode", - func(params []string, expected bool) { - Expect(IsNodeAuthorizationModeIncluded(params)).To(Equal(expected)) - }, - Entry("Is not explicitly enabled on insecure cluster", []string{}, false), - Entry("Is not present on insecure cluster", []string{"--authorization-mode=Foo,Bar"}, false), - Entry("Is not explicitly enabled on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Should present on CIS-compliant cluster", kubeApiServerCISCompliant, true), - Entry("Should present on Dublin cluster", kubeApiServerDublin, true), - ) - }) - - Describe("Flags requiring strict equality", func() { - DescribeTable("Strong Cryptographic Ciphers", - func(params []string, expected bool) { - Expect(IsStrongCryptoCipherInUse(params)).To(Equal(expected)) - }, - Entry("Is absent on insecure cluster", []string{}, false), - Entry("Is empty on insecure cluster", []string{"--tls-cipher-suites="}, false), - Entry("Is incomplete on insecure cluster", []string{"--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, false), - Entry("Is incomplete on Casablanca cluster", kubeApiServerCasablanca, false), - Entry("Is incomplete on Dublin cluster", kubeApiServerDublin, false), - Entry("Should be complete on CIS-compliant cluster", kubeApiServerCISCompliant, true), - ) - }) -}) diff --git a/test/security/k8s/src/check/validators/master/master.go b/test/security/k8s/src/check/validators/master/master.go new file mode 100644 index 000000000..e9dc66cc6 --- /dev/null +++ b/test/security/k8s/src/check/validators/master/master.go @@ -0,0 +1,57 @@ +package master + +import ( + "log" + + "check/validators/master/api" +) + +// Check validates master node complies with CIS guideliness. +func Check(k8sParams []string) { + log.Printf("IsBasicAuthFileAbsent: %t\n", api.IsBasicAuthFileAbsent(k8sParams)) + log.Printf("IsTokenAuthFileAbsent: %t\n", api.IsTokenAuthFileAbsent(k8sParams)) + log.Printf("IsInsecureAllowAnyTokenAbsent: %t\n", api.IsInsecureAllowAnyTokenAbsent(k8sParams)) + + log.Printf("IsAnonymousAuthDisabled: %t\n", api.IsAnonymousAuthDisabled(k8sParams)) + log.Printf("IsInsecurePortUnbound: %t\n", api.IsInsecurePortUnbound(k8sParams)) + log.Printf("IsProfilingDisabled: %t\n", api.IsProfilingDisabled(k8sParams)) + log.Printf("IsRepairMalformedUpdatesDisabled: %t\n", api.IsRepairMalformedUpdatesDisabled(k8sParams)) + log.Printf("IsServiceAccountLookupEnabled: %t\n", api.IsServiceAccountLookupEnabled(k8sParams)) + + log.Printf("IsKubeletHTTPSAbsentOrEnabled: %t\n", api.IsKubeletHTTPSAbsentOrEnabled(k8sParams)) + log.Printf("IsInsecureBindAddressAbsentOrLoopback: %t\n", api.IsInsecureBindAddressAbsentOrLoopback(k8sParams)) + log.Printf("IsSecurePortAbsentOrValid: %t\n", api.IsSecurePortAbsentOrValid(k8sParams)) + + log.Printf("IsAlwaysAdmitAdmissionControlPluginExcluded: %t\n", api.IsAlwaysAdmitAdmissionControlPluginExcluded(k8sParams)) + + log.Printf("IsAlwaysPullImagesAdmissionControlPluginIncluded: %t\n", api.IsAlwaysPullImagesAdmissionControlPluginIncluded(k8sParams)) + log.Printf("IsDenyEscalatingExecAdmissionControlPluginIncluded: %t\n", api.IsDenyEscalatingExecAdmissionControlPluginIncluded(k8sParams)) + log.Printf("IsSecurityContextDenyAdmissionControlPluginIncluded: %t\n", api.IsSecurityContextDenyAdmissionControlPluginIncluded(k8sParams)) + log.Printf("IsPodSecurityPolicyAdmissionControlPluginIncluded: %t\n", api.IsPodSecurityPolicyAdmissionControlPluginIncluded(k8sParams)) + log.Printf("IsServiceAccountAdmissionControlPluginIncluded: %t\n", api.IsServiceAccountAdmissionControlPluginIncluded(k8sParams)) + log.Printf("IsNodeRestrictionAdmissionControlPluginIncluded: %t\n", api.IsNodeRestrictionAdmissionControlPluginIncluded(k8sParams)) + log.Printf("IsEventRateLimitAdmissionControlPluginIncluded: %t\n", api.IsEventRateLimitAdmissionControlPluginIncluded(k8sParams)) + + log.Printf("IsNamespaceLifecycleAdmissionControlPluginNotExcluded: %t\n", api.IsNamespaceLifecycleAdmissionControlPluginNotExcluded(k8sParams)) + + log.Printf("IsAlwaysAllowAuthorizationModeExcluded: %t\n", api.IsAlwaysAllowAuthorizationModeExcluded(k8sParams)) + log.Printf("IsNodeAuthorizationModeIncluded: %t\n", api.IsNodeAuthorizationModeIncluded(k8sParams)) + + log.Printf("IsAuditLogPathSet: %t\n", api.IsAuditLogPathSet(k8sParams)) + log.Printf("IsAuditLogMaxAgeValid: %t\n", api.IsAuditLogMaxAgeValid(k8sParams)) + log.Printf("IsAuditLogMaxBackupValid: %t\n", api.IsAuditLogMaxBackupValid(k8sParams)) + log.Printf("IsAuditLogMaxSizeValid: %t\n", api.IsAuditLogMaxSizeValid(k8sParams)) + + log.Printf("IsRequestTimeoutValid: %t\n", api.IsRequestTimeoutValid(k8sParams)) + + log.Printf("IsKubeletCertificateAuthoritySet: %t\n", api.IsKubeletCertificateAuthoritySet(k8sParams)) + log.Printf("IsClientCertificateAuthoritySet: %t\n", api.IsClientCertificateAuthoritySet(k8sParams)) + log.Printf("IsEtcdCertificateAuthoritySet: %t\n", api.IsEtcdCertificateAuthoritySet(k8sParams)) + + log.Printf("IsServiceAccountKeySet: %t\n", api.IsServiceAccountKeySet(k8sParams)) + log.Printf("IsKubeletClientCertificateAndKeySet: %t\n", api.IsKubeletClientCertificateAndKeySet(k8sParams)) + log.Printf("IsEtcdCertificateAndKeySet: %t\n", api.IsEtcdCertificateAndKeySet(k8sParams)) + log.Printf("IsTLSCertificateAndKeySet: %t\n", api.IsTLSCertificateAndKeySet(k8sParams)) + + log.Printf("IsStrongCryptoCipherInUse: %t\n", api.IsStrongCryptoCipherInUse(k8sParams)) +} diff --git a/test/security/k8s/src/check/validators/master/master_suite_test.go b/test/security/k8s/src/check/validators/master/master_suite_test.go deleted file mode 100644 index 5c957d897..000000000 --- a/test/security/k8s/src/check/validators/master/master_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package master_test - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestMaster(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Master Suite") -} -- cgit 1.2.3-korg