Skip to content

Commit 5fb9e35

Browse files
authored
Merge pull request kubernetes#90191 from liggitt/csr-status
CSR condition status, lastTransitionTime, versioned validation
2 parents 5592b5d + 7049149 commit 5fb9e35

File tree

45 files changed

+2116
-172
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2116
-172
lines changed

api/openapi-spec/swagger.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/certificates/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ go_library(
1616
],
1717
importpath = "k8s.io/kubernetes/pkg/apis/certificates",
1818
deps = [
19+
"//pkg/apis/core:go_default_library",
1920
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2021
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
2122
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",

pkg/apis/certificates/types.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ limitations under the License.
1616

1717
package certificates
1818

19-
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
api "k8s.io/kubernetes/pkg/apis/core"
22+
)
2023

2124
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
2225

@@ -72,6 +75,28 @@ type CertificateSigningRequestSpec struct {
7275
Extra map[string]ExtraValue
7376
}
7477

78+
// Built in signerName values that are honoured by kube-controller-manager.
79+
// None of these usages are related to ServiceAccount token secrets
80+
// `.data[ca.crt]` in any way.
81+
const (
82+
// Signs certificates that will be honored as client-certs by the
83+
// kube-apiserver. Never auto-approved by kube-controller-manager.
84+
KubeAPIServerClientSignerName = "kubernetes.io/kube-apiserver-client"
85+
86+
// Signs client certificates that will be honored as client-certs by the
87+
// kube-apiserver for a kubelet.
88+
// May be auto-approved by kube-controller-manager.
89+
KubeAPIServerClientKubeletSignerName = "kubernetes.io/kube-apiserver-client-kubelet"
90+
91+
// Signs serving certificates that are honored as a valid kubelet serving
92+
// certificate by the kube-apiserver, but has no other guarantees.
93+
KubeletServingSignerName = "kubernetes.io/kubelet-serving"
94+
95+
// Has no guarantees for trust at all. Some distributions may honor these
96+
// as client certs, but that behavior is not standard kubernetes behavior.
97+
LegacyUnknownSignerName = "kubernetes.io/legacy-unknown"
98+
)
99+
75100
// ExtraValue masks the value so protobuf can generate
76101
type ExtraValue []string
77102

@@ -91,11 +116,17 @@ type RequestConditionType string
91116
const (
92117
CertificateApproved RequestConditionType = "Approved"
93118
CertificateDenied RequestConditionType = "Denied"
119+
CertificateFailed RequestConditionType = "Failed"
94120
)
95121

96122
type CertificateSigningRequestCondition struct {
97-
// request approval state, currently Approved or Denied.
123+
// type of the condition. Known conditions include "Approved", "Denied", and "Failed".
98124
Type RequestConditionType
125+
// Status of the condition, one of True, False, Unknown.
126+
// Approved, Denied, and Failed conditions may not be "False" or "Unknown".
127+
// If unset, should be treated as "True".
128+
// +optional
129+
Status api.ConditionStatus
99130
// brief reason for the request state
100131
// +optional
101132
Reason string
@@ -105,6 +136,9 @@ type CertificateSigningRequestCondition struct {
105136
// timestamp for the last update to this condition
106137
// +optional
107138
LastUpdateTime metav1.Time
139+
// lastTransitionTime is the time the condition last transitioned from one status to another.
140+
// +optional
141+
LastTransitionTime metav1.Time
108142
}
109143

110144
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

pkg/apis/certificates/v1beta1/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ go_library(
2020
importpath = "k8s.io/kubernetes/pkg/apis/certificates/v1beta1",
2121
deps = [
2222
"//pkg/apis/certificates:go_default_library",
23+
"//pkg/apis/core:go_default_library",
2324
"//staging/src/k8s.io/api/certificates/v1beta1:go_default_library",
25+
"//staging/src/k8s.io/api/core/v1:go_default_library",
2426
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2527
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
2628
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",

pkg/apis/certificates/v1beta1/defaults.go

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ package v1beta1
1818

1919
import (
2020
"crypto/x509"
21+
"fmt"
2122
"reflect"
2223
"strings"
2324

2425
certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
26+
v1 "k8s.io/api/core/v1"
2527
"k8s.io/apimachinery/pkg/runtime"
2628
"k8s.io/apimachinery/pkg/util/sets"
2729
)
@@ -41,6 +43,12 @@ func SetDefaults_CertificateSigningRequestSpec(obj *certificatesv1beta1.Certific
4143
}
4244
}
4345

46+
func SetDefaults_CertificateSigningRequestCondition(obj *certificatesv1beta1.CertificateSigningRequestCondition) {
47+
if len(obj.Status) == 0 {
48+
obj.Status = v1.ConditionTrue
49+
}
50+
}
51+
4452
// DefaultSignerNameFromSpec will determine the signerName that should be set
4553
// by attempting to inspect the 'request' content and the spec options.
4654
func DefaultSignerNameFromSpec(obj *certificatesv1beta1.CertificateSigningRequestSpec) string {
@@ -59,18 +67,34 @@ func DefaultSignerNameFromSpec(obj *certificatesv1beta1.CertificateSigningReques
5967
}
6068
}
6169

70+
var (
71+
organizationNotSystemNodesErr = fmt.Errorf("subject organization is not system:nodes")
72+
commonNameNotSystemNode = fmt.Errorf("subject common name does not begin with system:node:")
73+
dnsOrIPSANRequiredErr = fmt.Errorf("DNS or IP subjectAltName is required")
74+
dnsSANNotAllowedErr = fmt.Errorf("DNS subjectAltNames are not allowed")
75+
emailSANNotAllowedErr = fmt.Errorf("Email subjectAltNames are not allowed")
76+
ipSANNotAllowedErr = fmt.Errorf("IP subjectAltNames are not allowed")
77+
uriSANNotAllowedErr = fmt.Errorf("URI subjectAltNames are not allowed")
78+
)
79+
6280
func IsKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool {
81+
return ValidateKubeletServingCSR(req, usages) == nil
82+
}
83+
func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error {
6384
if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) {
64-
return false
85+
return organizationNotSystemNodesErr
6586
}
6687

6788
// at least one of dnsNames or ipAddresses must be specified
6889
if len(req.DNSNames) == 0 && len(req.IPAddresses) == 0 {
69-
return false
90+
return dnsOrIPSANRequiredErr
7091
}
7192

72-
if len(req.EmailAddresses) > 0 || len(req.URIs) > 0 {
73-
return false
93+
if len(req.EmailAddresses) > 0 {
94+
return emailSANNotAllowedErr
95+
}
96+
if len(req.URIs) > 0 {
97+
return uriSANNotAllowedErr
7498
}
7599

76100
requiredUsages := []certificatesv1beta1.KeyUsage{
@@ -79,27 +103,39 @@ func IsKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1be
79103
certificatesv1beta1.UsageServerAuth,
80104
}
81105
if !equalUnsorted(requiredUsages, usages) {
82-
return false
106+
return fmt.Errorf("usages did not match %v", requiredUsages)
83107
}
84108

85109
if !strings.HasPrefix(req.Subject.CommonName, "system:node:") {
86-
return false
110+
return commonNameNotSystemNode
87111
}
88112

89-
return true
113+
return nil
90114
}
91115

92116
func IsKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool {
117+
return ValidateKubeletClientCSR(req, usages) == nil
118+
}
119+
func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error {
93120
if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) {
94-
return false
121+
return organizationNotSystemNodesErr
95122
}
96123

97-
if len(req.DNSNames) > 0 || len(req.EmailAddresses) > 0 || len(req.IPAddresses) > 0 || len(req.URIs) > 0 {
98-
return false
124+
if len(req.DNSNames) > 0 {
125+
return dnsSANNotAllowedErr
126+
}
127+
if len(req.EmailAddresses) > 0 {
128+
return emailSANNotAllowedErr
129+
}
130+
if len(req.IPAddresses) > 0 {
131+
return ipSANNotAllowedErr
132+
}
133+
if len(req.URIs) > 0 {
134+
return uriSANNotAllowedErr
99135
}
100136

101137
if !strings.HasPrefix(req.Subject.CommonName, "system:node:") {
102-
return false
138+
return commonNameNotSystemNode
103139
}
104140

105141
requiredUsages := []certificatesv1beta1.KeyUsage{
@@ -108,10 +144,10 @@ func IsKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1bet
108144
certificatesv1beta1.UsageClientAuth,
109145
}
110146
if !equalUnsorted(requiredUsages, usages) {
111-
return false
147+
return fmt.Errorf("usages did not match %v", requiredUsages)
112148
}
113149

114-
return true
150+
return nil
115151
}
116152

117153
// equalUnsorted compares two []string for equality of contents regardless of

pkg/apis/certificates/v1beta1/zz_generated.conversion.go

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/certificates/v1beta1/zz_generated.defaults.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/certificates/validation/BUILD

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,16 @@ go_library(
1212
importpath = "k8s.io/kubernetes/pkg/apis/certificates/validation",
1313
deps = [
1414
"//pkg/apis/certificates:go_default_library",
15+
"//pkg/apis/certificates/v1beta1:go_default_library",
1516
"//pkg/apis/core/validation:go_default_library",
17+
"//staging/src/k8s.io/api/core/v1:go_default_library",
18+
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
19+
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
20+
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
21+
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
1622
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
1723
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
24+
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
1825
],
1926
)
2027

@@ -37,7 +44,11 @@ go_test(
3744
embed = [":go_default_library"],
3845
deps = [
3946
"//pkg/apis/certificates:go_default_library",
47+
"//pkg/apis/certificates/v1beta1:go_default_library",
48+
"//pkg/apis/core:go_default_library",
4049
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
50+
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
51+
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
4152
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
4253
],
4354
)

0 commit comments

Comments
 (0)