mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
certificates: support allowed usage
This commit is contained in:
parent
ee177dbbfe
commit
fb099ae385
@ -46,6 +46,12 @@ type CertificateSigningRequestSpec struct {
|
|||||||
// Base64-encoded PKCS#10 CSR data
|
// Base64-encoded PKCS#10 CSR data
|
||||||
Request []byte
|
Request []byte
|
||||||
|
|
||||||
|
// usages specifies a set of usage contexts the key will be
|
||||||
|
// valid for.
|
||||||
|
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||||
|
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
|
||||||
|
Usages []KeyUsage
|
||||||
|
|
||||||
// Information about the requesting user (if relevant)
|
// Information about the requesting user (if relevant)
|
||||||
// See user.Info interface for details
|
// See user.Info interface for details
|
||||||
// +optional
|
// +optional
|
||||||
@ -96,3 +102,34 @@ type CertificateSigningRequestList struct {
|
|||||||
// +optional
|
// +optional
|
||||||
Items []CertificateSigningRequest
|
Items []CertificateSigningRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyUsages specifies valid usage contexts for keys.
|
||||||
|
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||||
|
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
|
||||||
|
type KeyUsage string
|
||||||
|
|
||||||
|
const (
|
||||||
|
UsageSigning KeyUsage = "signing"
|
||||||
|
UsageDigitalSignature KeyUsage = "digital signature"
|
||||||
|
UsageContentCommittment KeyUsage = "content committment"
|
||||||
|
UsageKeyEncipherment KeyUsage = "key encipherment"
|
||||||
|
UsageKeyAgreement KeyUsage = "key agreement"
|
||||||
|
UsageDataEncipherment KeyUsage = "data encipherment"
|
||||||
|
UsageCertSign KeyUsage = "cert sign"
|
||||||
|
UsageCRLSign KeyUsage = "crl sign"
|
||||||
|
UsageEncipherOnly KeyUsage = "encipher only"
|
||||||
|
UsageDecipherOnly KeyUsage = "decipher only"
|
||||||
|
UsageAny KeyUsage = "any"
|
||||||
|
UsageServerAuth KeyUsage = "server auth"
|
||||||
|
UsageClientAuth KeyUsage = "client auth"
|
||||||
|
UsageCodeSigning KeyUsage = "code signing"
|
||||||
|
UsageEmailProtection KeyUsage = "email protection"
|
||||||
|
UsageSMIME KeyUsage = "s/mime"
|
||||||
|
UsageIPsecEndSystem KeyUsage = "ipsec end system"
|
||||||
|
UsageIPsecTunnel KeyUsage = "ipsec tunnel"
|
||||||
|
UsageIPsecUser KeyUsage = "ipsec user"
|
||||||
|
UsageTimestamping KeyUsage = "timestamping"
|
||||||
|
UsageOCSPSigning KeyUsage = "ocsp signing"
|
||||||
|
UsageMicrosoftSGC KeyUsage = "microsoft sgc"
|
||||||
|
UsageNetscapSGC KeyUsage = "netscape sgc"
|
||||||
|
)
|
||||||
|
@ -46,6 +46,12 @@ type CertificateSigningRequestSpec struct {
|
|||||||
// Base64-encoded PKCS#10 CSR data
|
// Base64-encoded PKCS#10 CSR data
|
||||||
Request []byte `json:"request" protobuf:"bytes,1,opt,name=request"`
|
Request []byte `json:"request" protobuf:"bytes,1,opt,name=request"`
|
||||||
|
|
||||||
|
// allowedUsages specifies a set of usage contexts the key will be
|
||||||
|
// valid for.
|
||||||
|
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||||
|
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
|
||||||
|
Usages []KeyUsage `json:"usages,omitempty" protobuf:"bytes,5,opt,name=keyUsage"`
|
||||||
|
|
||||||
// Information about the requesting user (if relevant)
|
// Information about the requesting user (if relevant)
|
||||||
// See user.Info interface for details
|
// See user.Info interface for details
|
||||||
// +optional
|
// +optional
|
||||||
@ -95,3 +101,34 @@ type CertificateSigningRequestList struct {
|
|||||||
|
|
||||||
Items []CertificateSigningRequest `json:"items" protobuf:"bytes,2,rep,name=items"`
|
Items []CertificateSigningRequest `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyUsages specifies valid usage contexts for keys.
|
||||||
|
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||||
|
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
|
||||||
|
type KeyUsage string
|
||||||
|
|
||||||
|
const (
|
||||||
|
UsageSigning KeyUsage = "signing"
|
||||||
|
UsageDigitalSignature KeyUsage = "digital signature"
|
||||||
|
UsageContentCommittment KeyUsage = "content committment"
|
||||||
|
UsageKeyEncipherment KeyUsage = "key encipherment"
|
||||||
|
UsageKeyAgreement KeyUsage = "key agreement"
|
||||||
|
UsageDataEncipherment KeyUsage = "data encipherment"
|
||||||
|
UsageCertSign KeyUsage = "cert sign"
|
||||||
|
UsageCRLSign KeyUsage = "crl sign"
|
||||||
|
UsageEncipherOnly KeyUsage = "encipher only"
|
||||||
|
UsageDecipherOnly KeyUsage = "decipher only"
|
||||||
|
UsageAny KeyUsage = "any"
|
||||||
|
UsageServerAuth KeyUsage = "server auth"
|
||||||
|
UsageClientAuth KeyUsage = "client auth"
|
||||||
|
UsageCodeSigning KeyUsage = "code signing"
|
||||||
|
UsageEmailProtection KeyUsage = "email protection"
|
||||||
|
UsageSMIME KeyUsage = "s/mime"
|
||||||
|
UsageIPsecEndSystem KeyUsage = "ipsec end system"
|
||||||
|
UsageIPsecTunnel KeyUsage = "ipsec tunnel"
|
||||||
|
UsageIPsecUser KeyUsage = "ipsec user"
|
||||||
|
UsageTimestamping KeyUsage = "timestamping"
|
||||||
|
UsageOCSPSigning KeyUsage = "ocsp signing"
|
||||||
|
UsageMicrosoftSGC KeyUsage = "microsoft sgc"
|
||||||
|
UsageNetscapSGC KeyUsage = "netscape sgc"
|
||||||
|
)
|
||||||
|
@ -32,6 +32,7 @@ go_library(
|
|||||||
"//pkg/util/workqueue:go_default_library",
|
"//pkg/util/workqueue:go_default_library",
|
||||||
"//pkg/watch:go_default_library",
|
"//pkg/watch:go_default_library",
|
||||||
"//vendor:github.com/cloudflare/cfssl/config",
|
"//vendor:github.com/cloudflare/cfssl/config",
|
||||||
|
"//vendor:github.com/cloudflare/cfssl/helpers",
|
||||||
"//vendor:github.com/cloudflare/cfssl/signer",
|
"//vendor:github.com/cloudflare/cfssl/signer",
|
||||||
"//vendor:github.com/cloudflare/cfssl/signer/local",
|
"//vendor:github.com/cloudflare/cfssl/signer/local",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
|
@ -33,9 +33,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
|
|
||||||
"github.com/cloudflare/cfssl/config"
|
|
||||||
"github.com/cloudflare/cfssl/signer"
|
|
||||||
"github.com/cloudflare/cfssl/signer/local"
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,6 +40,10 @@ type AutoApprover interface {
|
|||||||
AutoApprove(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error)
|
AutoApprove(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Signer interface {
|
||||||
|
Sign(csr *certificates.CertificateSigningRequest) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
type CertificateController struct {
|
type CertificateController struct {
|
||||||
kubeClient clientset.Interface
|
kubeClient clientset.Interface
|
||||||
|
|
||||||
@ -53,8 +54,7 @@ type CertificateController struct {
|
|||||||
syncHandler func(csrKey string) error
|
syncHandler func(csrKey string) error
|
||||||
|
|
||||||
approver AutoApprover
|
approver AutoApprover
|
||||||
|
signer Signer
|
||||||
signer *local.Signer
|
|
||||||
|
|
||||||
queue workqueue.RateLimitingInterface
|
queue workqueue.RateLimitingInterface
|
||||||
}
|
}
|
||||||
@ -65,12 +65,7 @@ func NewCertificateController(kubeClient clientset.Interface, syncPeriod time.Du
|
|||||||
eventBroadcaster.StartLogging(glog.Infof)
|
eventBroadcaster.StartLogging(glog.Infof)
|
||||||
eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.Core().Events("")})
|
eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.Core().Events("")})
|
||||||
|
|
||||||
// Configure cfssl signer
|
s, err := NewCFSSLSigner(caCertFile, caKeyFile)
|
||||||
// TODO: support non-default policy and remote/pkcs11 signing
|
|
||||||
policy := &config.Signing{
|
|
||||||
Default: config.DefaultConfig(),
|
|
||||||
}
|
|
||||||
ca, err := local.NewSignerFromFile(caCertFile, caKeyFile, policy)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -78,7 +73,7 @@ func NewCertificateController(kubeClient clientset.Interface, syncPeriod time.Du
|
|||||||
cc := &CertificateController{
|
cc := &CertificateController{
|
||||||
kubeClient: kubeClient,
|
kubeClient: kubeClient,
|
||||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "certificate"),
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "certificate"),
|
||||||
signer: ca,
|
signer: s,
|
||||||
approver: approver,
|
approver: approver,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,9 +204,7 @@ func (cc *CertificateController) maybeSignCertificate(key string) error {
|
|||||||
// 3. Update the Status subresource
|
// 3. Update the Status subresource
|
||||||
|
|
||||||
if csr.Status.Certificate == nil && IsCertificateRequestApproved(csr) {
|
if csr.Status.Certificate == nil && IsCertificateRequestApproved(csr) {
|
||||||
pemBytes := csr.Spec.Request
|
certBytes, err := cc.signer.Sign(csr)
|
||||||
req := signer.SignRequest{Request: string(pemBytes)}
|
|
||||||
certBytes, err := cc.signer.Sign(req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
99
pkg/controller/certificates/cfssl_signer.go
Normal file
99
pkg/controller/certificates/cfssl_signer.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package certificates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
certificates "k8s.io/kubernetes/pkg/apis/certificates/v1alpha1"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cfssl/config"
|
||||||
|
"github.com/cloudflare/cfssl/helpers"
|
||||||
|
"github.com/cloudflare/cfssl/signer"
|
||||||
|
"github.com/cloudflare/cfssl/signer/local"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onlySigningPolicy = &config.Signing{
|
||||||
|
Default: &config.SigningProfile{
|
||||||
|
Usage: []string{"signing"},
|
||||||
|
Expiry: helpers.OneYear,
|
||||||
|
ExpiryString: "8760h",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type CFSSLSigner struct {
|
||||||
|
ca *x509.Certificate
|
||||||
|
priv crypto.Signer
|
||||||
|
sigAlgo x509.SignatureAlgorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCFSSLSigner(caFile, caKeyFile string) (*CFSSLSigner, error) {
|
||||||
|
ca, err := ioutil.ReadFile(caFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cakey, err := ioutil.ReadFile(caKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedCa, err := helpers.ParseCertificatePEM(ca)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD")
|
||||||
|
password := []byte(strPassword)
|
||||||
|
if strPassword == "" {
|
||||||
|
password = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Malformed private key %v", err)
|
||||||
|
}
|
||||||
|
return &CFSSLSigner{
|
||||||
|
priv: priv,
|
||||||
|
ca: parsedCa,
|
||||||
|
sigAlgo: signer.DefaultSigAlgo(priv),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *CFSSLSigner) Sign(csr *certificates.CertificateSigningRequest) ([]byte, error) {
|
||||||
|
var usages []string
|
||||||
|
for _, usage := range csr.Spec.Usages {
|
||||||
|
usages = append(usages, string(usage))
|
||||||
|
}
|
||||||
|
policy := &config.Signing{
|
||||||
|
Default: &config.SigningProfile{
|
||||||
|
Usage: usages,
|
||||||
|
Expiry: helpers.OneYear,
|
||||||
|
ExpiryString: "8760h",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s, err := local.NewSigner(cs.priv, cs.ca, cs.sigAlgo, policy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.Sign(signer.SignRequest{
|
||||||
|
Request: string(csr.Spec.Request),
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user