mirror of https://github.com/kubernetes/kops.git
Merge pull request #3679 from justinsb/support_api_aggregation
Automatic merge from submit-queue.
Initial aggregation work
Create the keypairs, which are supposed to be signed by a different CA.
Set the `--requestheader-...` flags on apiserver.
Fix #3152
Fix #2691
This commit is contained in:
commit
8df13bd468
|
|
@ -116,7 +116,7 @@ func (c *NodeupModelContext) CNIConfDir() string {
|
|||
|
||||
// buildPKIKubeconfig generates a kubeconfig
|
||||
func (c *NodeupModelContext) buildPKIKubeconfig(id string) (string, error) {
|
||||
caCertificate, err := c.KeyStore.Cert(fi.CertificateId_CA, false)
|
||||
caCertificate, err := c.KeyStore.FindCert(fi.CertificateId_CA)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error fetching CA certificate from keystore: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,12 +184,25 @@ func (b *KubeAPIServerBuilder) buildPod() (*v1.Pod, error) {
|
|||
}
|
||||
|
||||
if b.IsKubernetesGTE("1.7") {
|
||||
certPath := filepath.Join(b.PathSrvKubernetes(), "proxy-client.cert")
|
||||
certPath := filepath.Join(b.PathSrvKubernetes(), "apiserver-aggregator.cert")
|
||||
kubeAPIServer.ProxyClientCertFile = &certPath
|
||||
keyPath := filepath.Join(b.PathSrvKubernetes(), "proxy-client.key")
|
||||
keyPath := filepath.Join(b.PathSrvKubernetes(), "apiserver-aggregator.key")
|
||||
kubeAPIServer.ProxyClientKeyFile = &keyPath
|
||||
}
|
||||
|
||||
// APIServer aggregation options
|
||||
if b.IsKubernetesGTE("1.7") {
|
||||
cert, err := b.KeyStore.FindCert("apiserver-aggregator-ca")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("apiserver aggregator CA cert lookup failed: %v", err.Error())
|
||||
}
|
||||
|
||||
if cert != nil {
|
||||
certPath := filepath.Join(b.PathSrvKubernetes(), "apiserver-aggregator-ca.cert")
|
||||
kubeAPIServer.RequestheaderClientCAFile = certPath
|
||||
}
|
||||
}
|
||||
|
||||
// build the kube-apiserver flags for the service
|
||||
flags, err := flagbuilder.BuildFlagsList(b.Cluster.Spec.KubeAPIServer)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
|
||||
)
|
||||
|
|
@ -117,7 +118,7 @@ func (b *SecretBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
}
|
||||
|
||||
if b.IsKubernetesGTE("1.7") {
|
||||
|
||||
// TODO: Remove - we use the apiserver-aggregator keypair instead (which is signed by a different CA)
|
||||
cert, err := b.KeyStore.Cert("apiserver-proxy-client", false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("apiserver proxy client cert lookup failed: %v", err.Error())
|
||||
|
|
@ -153,6 +154,22 @@ func (b *SecretBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
c.AddTask(t)
|
||||
}
|
||||
|
||||
if b.IsKubernetesGTE("1.7") {
|
||||
if err := b.writeCertificate(c, "apiserver-aggregator"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := b.writePrivateKey(c, "apiserver-aggregator"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if b.IsKubernetesGTE("1.7") {
|
||||
if err := b.writeCertificate(c, "apiserver-aggregator-ca"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if b.SecretStore != nil {
|
||||
key := "kube"
|
||||
token, err := b.SecretStore.FindSecret(key)
|
||||
|
|
@ -200,6 +217,55 @@ func (b *SecretBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// writeCertificate writes the specified certificate to the local filesystem, under PathSrvKubernetes()
|
||||
func (b *SecretBuilder) writeCertificate(c *fi.ModelBuilderContext, id string) error {
|
||||
cert, err := b.KeyStore.FindCert(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cert lookup failed for %q: %v", id, err)
|
||||
}
|
||||
|
||||
if cert != nil {
|
||||
serialized, err := cert.AsString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t := &nodetasks.File{
|
||||
Path: filepath.Join(b.PathSrvKubernetes(), id+".cert"),
|
||||
Contents: fi.NewStringResource(serialized),
|
||||
Type: nodetasks.FileType_File,
|
||||
}
|
||||
c.AddTask(t)
|
||||
} else {
|
||||
// TODO: Make this an error?
|
||||
glog.Warningf("certificate %q not found", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writePrivateKey writes the specified private key to the local filesystem, under PathSrvKubernetes()
|
||||
func (b *SecretBuilder) writePrivateKey(c *fi.ModelBuilderContext, id string) error {
|
||||
key, err := b.KeyStore.FindPrivateKey(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("private key lookup failed for %q: %v", id, err)
|
||||
}
|
||||
|
||||
serialized, err := key.AsString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t := &nodetasks.File{
|
||||
Path: filepath.Join(b.PathSrvKubernetes(), id+".key"),
|
||||
Contents: fi.NewStringResource(serialized),
|
||||
Type: nodetasks.FileType_File,
|
||||
}
|
||||
c.AddTask(t)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// allTokens returns a map of all tokens
|
||||
func (b *SecretBuilder) allTokens() (map[string]string, error) {
|
||||
tokens := make(map[string]string)
|
||||
|
|
|
|||
|
|
@ -258,6 +258,17 @@ type KubeAPIServerConfig struct {
|
|||
AuthorizationRBACSuperUser *string `json:"authorizationRbacSuperUser,omitempty" flag:"authorization-rbac-super-user"`
|
||||
// ExperimentalEncryptionProviderConfig enables encryption at rest for secrets.
|
||||
ExperimentalEncryptionProviderConfig *string `json:"experimentalEncryptionProviderConfig,omitempty" flag:"experimental-encryption-provider-config"`
|
||||
|
||||
// List of request headers to inspect for usernames. X-Remote-User is common.
|
||||
RequestheaderUsernameHeaders []string `json:"requestheaderUsernameHeaders,omitempty" flag:"requestheader-username-headers"`
|
||||
// List of request headers to inspect for groups. X-Remote-Group is suggested.
|
||||
RequestheaderGroupHeaders []string `json:"requestheaderGroupHeaders,omitempty" flag:"requestheader-group-headers"`
|
||||
// List of request header prefixes to inspect. X-Remote-Extra- is suggested.
|
||||
RequestheaderExtraHeaderPrefixes []string `json:"requestheaderExtraHeaderPrefixes,omitempty" flag:"requestheader-extra-headers-prefix"`
|
||||
//Root certificate bundle to use to verify client certificates on incoming requests before trusting usernames in headers specified by --requestheader-username-headers
|
||||
RequestheaderClientCAFile string `json:"requestheaderClientCAFile,omitempty" flag:"requestheader-client-ca-file"`
|
||||
// List of client certificate common names to allow to provide usernames in headers specified by --requestheader-username-headers. If empty, any client certificate validated by the authorities in --requestheader-client-ca-file is allowed.
|
||||
RequestheaderAllowedNames []string `json:"requestheaderAllowedNames,omitempty" flag:"requestheader-allowed-names"`
|
||||
}
|
||||
|
||||
// KubeControllerManagerConfig is the configuration for the controller
|
||||
|
|
|
|||
|
|
@ -258,6 +258,17 @@ type KubeAPIServerConfig struct {
|
|||
AuthorizationRBACSuperUser *string `json:"authorizationRbacSuperUser,omitempty" flag:"authorization-rbac-super-user"`
|
||||
// ExperimentalEncryptionProviderConfig enables encryption at rest for secrets.
|
||||
ExperimentalEncryptionProviderConfig *string `json:"experimentalEncryptionProviderConfig,omitempty" flag:"experimental-encryption-provider-config"`
|
||||
|
||||
// List of request headers to inspect for usernames. X-Remote-User is common.
|
||||
RequestheaderUsernameHeaders []string `json:"requestheaderUsernameHeaders,omitempty" flag:"requestheader-username-headers"`
|
||||
// List of request headers to inspect for groups. X-Remote-Group is suggested.
|
||||
RequestheaderGroupHeaders []string `json:"requestheaderGroupHeaders,omitempty" flag:"requestheader-group-headers"`
|
||||
// List of request header prefixes to inspect. X-Remote-Extra- is suggested.
|
||||
RequestheaderExtraHeaderPrefixes []string `json:"requestheaderExtraHeaderPrefixes,omitempty" flag:"requestheader-extra-headers-prefix"`
|
||||
//Root certificate bundle to use to verify client certificates on incoming requests before trusting usernames in headers specified by --requestheader-username-headers
|
||||
RequestheaderClientCAFile string `json:"requestheaderClientCAFile,omitempty" flag:"requestheader-client-ca-file"`
|
||||
// List of client certificate common names to allow to provide usernames in headers specified by --requestheader-username-headers. If empty, any client certificate validated by the authorities in --requestheader-client-ca-file is allowed.
|
||||
RequestheaderAllowedNames []string `json:"requestheaderAllowedNames,omitempty" flag:"requestheader-allowed-names"`
|
||||
}
|
||||
|
||||
// KubeControllerManagerConfig is the configuration for the controller
|
||||
|
|
|
|||
|
|
@ -1816,6 +1816,11 @@ func autoConvert_v1alpha1_KubeAPIServerConfig_To_kops_KubeAPIServerConfig(in *Ku
|
|||
out.AuthorizationMode = in.AuthorizationMode
|
||||
out.AuthorizationRBACSuperUser = in.AuthorizationRBACSuperUser
|
||||
out.ExperimentalEncryptionProviderConfig = in.ExperimentalEncryptionProviderConfig
|
||||
out.RequestheaderUsernameHeaders = in.RequestheaderUsernameHeaders
|
||||
out.RequestheaderGroupHeaders = in.RequestheaderGroupHeaders
|
||||
out.RequestheaderExtraHeaderPrefixes = in.RequestheaderExtraHeaderPrefixes
|
||||
out.RequestheaderClientCAFile = in.RequestheaderClientCAFile
|
||||
out.RequestheaderAllowedNames = in.RequestheaderAllowedNames
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1868,6 +1873,11 @@ func autoConvert_kops_KubeAPIServerConfig_To_v1alpha1_KubeAPIServerConfig(in *ko
|
|||
out.AuthorizationMode = in.AuthorizationMode
|
||||
out.AuthorizationRBACSuperUser = in.AuthorizationRBACSuperUser
|
||||
out.ExperimentalEncryptionProviderConfig = in.ExperimentalEncryptionProviderConfig
|
||||
out.RequestheaderUsernameHeaders = in.RequestheaderUsernameHeaders
|
||||
out.RequestheaderGroupHeaders = in.RequestheaderGroupHeaders
|
||||
out.RequestheaderExtraHeaderPrefixes = in.RequestheaderExtraHeaderPrefixes
|
||||
out.RequestheaderClientCAFile = in.RequestheaderClientCAFile
|
||||
out.RequestheaderAllowedNames = in.RequestheaderAllowedNames
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2035,6 +2035,26 @@ func (in *KubeAPIServerConfig) DeepCopyInto(out *KubeAPIServerConfig) {
|
|||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.RequestheaderUsernameHeaders != nil {
|
||||
in, out := &in.RequestheaderUsernameHeaders, &out.RequestheaderUsernameHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderGroupHeaders != nil {
|
||||
in, out := &in.RequestheaderGroupHeaders, &out.RequestheaderGroupHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderExtraHeaderPrefixes != nil {
|
||||
in, out := &in.RequestheaderExtraHeaderPrefixes, &out.RequestheaderExtraHeaderPrefixes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderAllowedNames != nil {
|
||||
in, out := &in.RequestheaderAllowedNames, &out.RequestheaderAllowedNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -258,6 +258,17 @@ type KubeAPIServerConfig struct {
|
|||
AuthorizationRBACSuperUser *string `json:"authorizationRbacSuperUser,omitempty" flag:"authorization-rbac-super-user"`
|
||||
// ExperimentalEncryptionProviderConfig enables encryption at rest for secrets.
|
||||
ExperimentalEncryptionProviderConfig *string `json:"experimentalEncryptionProviderConfig,omitempty" flag:"experimental-encryption-provider-config"`
|
||||
|
||||
// List of request headers to inspect for usernames. X-Remote-User is common.
|
||||
RequestheaderUsernameHeaders []string `json:"requestheaderUsernameHeaders,omitempty" flag:"requestheader-username-headers"`
|
||||
// List of request headers to inspect for groups. X-Remote-Group is suggested.
|
||||
RequestheaderGroupHeaders []string `json:"requestheaderGroupHeaders,omitempty" flag:"requestheader-group-headers"`
|
||||
// List of request header prefixes to inspect. X-Remote-Extra- is suggested.
|
||||
RequestheaderExtraHeaderPrefixes []string `json:"requestheaderExtraHeaderPrefixes,omitempty" flag:"requestheader-extra-headers-prefix"`
|
||||
//Root certificate bundle to use to verify client certificates on incoming requests before trusting usernames in headers specified by --requestheader-username-headers
|
||||
RequestheaderClientCAFile string `json:"requestheaderClientCAFile,omitempty" flag:"requestheader-client-ca-file"`
|
||||
// List of client certificate common names to allow to provide usernames in headers specified by --requestheader-username-headers. If empty, any client certificate validated by the authorities in --requestheader-client-ca-file is allowed.
|
||||
RequestheaderAllowedNames []string `json:"requestheaderAllowedNames,omitempty" flag:"requestheader-allowed-names"`
|
||||
}
|
||||
|
||||
// KubeControllerManagerConfig is the configuration for the controller
|
||||
|
|
|
|||
|
|
@ -2078,6 +2078,11 @@ func autoConvert_v1alpha2_KubeAPIServerConfig_To_kops_KubeAPIServerConfig(in *Ku
|
|||
out.AuthorizationMode = in.AuthorizationMode
|
||||
out.AuthorizationRBACSuperUser = in.AuthorizationRBACSuperUser
|
||||
out.ExperimentalEncryptionProviderConfig = in.ExperimentalEncryptionProviderConfig
|
||||
out.RequestheaderUsernameHeaders = in.RequestheaderUsernameHeaders
|
||||
out.RequestheaderGroupHeaders = in.RequestheaderGroupHeaders
|
||||
out.RequestheaderExtraHeaderPrefixes = in.RequestheaderExtraHeaderPrefixes
|
||||
out.RequestheaderClientCAFile = in.RequestheaderClientCAFile
|
||||
out.RequestheaderAllowedNames = in.RequestheaderAllowedNames
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -2130,6 +2135,11 @@ func autoConvert_kops_KubeAPIServerConfig_To_v1alpha2_KubeAPIServerConfig(in *ko
|
|||
out.AuthorizationMode = in.AuthorizationMode
|
||||
out.AuthorizationRBACSuperUser = in.AuthorizationRBACSuperUser
|
||||
out.ExperimentalEncryptionProviderConfig = in.ExperimentalEncryptionProviderConfig
|
||||
out.RequestheaderUsernameHeaders = in.RequestheaderUsernameHeaders
|
||||
out.RequestheaderGroupHeaders = in.RequestheaderGroupHeaders
|
||||
out.RequestheaderExtraHeaderPrefixes = in.RequestheaderExtraHeaderPrefixes
|
||||
out.RequestheaderClientCAFile = in.RequestheaderClientCAFile
|
||||
out.RequestheaderAllowedNames = in.RequestheaderAllowedNames
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2161,6 +2161,26 @@ func (in *KubeAPIServerConfig) DeepCopyInto(out *KubeAPIServerConfig) {
|
|||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.RequestheaderUsernameHeaders != nil {
|
||||
in, out := &in.RequestheaderUsernameHeaders, &out.RequestheaderUsernameHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderGroupHeaders != nil {
|
||||
in, out := &in.RequestheaderGroupHeaders, &out.RequestheaderGroupHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderExtraHeaderPrefixes != nil {
|
||||
in, out := &in.RequestheaderExtraHeaderPrefixes, &out.RequestheaderExtraHeaderPrefixes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderAllowedNames != nil {
|
||||
in, out := &in.RequestheaderAllowedNames, &out.RequestheaderAllowedNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2380,6 +2380,26 @@ func (in *KubeAPIServerConfig) DeepCopyInto(out *KubeAPIServerConfig) {
|
|||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.RequestheaderUsernameHeaders != nil {
|
||||
in, out := &in.RequestheaderUsernameHeaders, &out.RequestheaderUsernameHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderGroupHeaders != nil {
|
||||
in, out := &in.RequestheaderGroupHeaders, &out.RequestheaderGroupHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderExtraHeaderPrefixes != nil {
|
||||
in, out := &in.RequestheaderExtraHeaderPrefixes, &out.RequestheaderExtraHeaderPrefixes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequestheaderAllowedNames != nil {
|
||||
in, out := &in.RequestheaderAllowedNames, &out.RequestheaderAllowedNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ func (b *KubeAPIServerOptionsBuilder) BuildOptions(o interface{}) error {
|
|||
clusterSpec.KubeAPIServer.AuthorizationMode = fi.String("RBAC")
|
||||
}
|
||||
|
||||
if err := b.configureAggregation(clusterSpec); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
image, err := Image("kube-apiserver", clusterSpec, b.AssetBuilder)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -247,3 +251,15 @@ func (b *KubeAPIServerOptionsBuilder) buildAPIServerCount(clusterSpec *kops.Clus
|
|||
|
||||
return count
|
||||
}
|
||||
|
||||
// configureAggregation sets up the aggregation options
|
||||
func (b *KubeAPIServerOptionsBuilder) configureAggregation(clusterSpec *kops.ClusterSpec) error {
|
||||
if b.IsKubernetesGTE("1.7") {
|
||||
clusterSpec.KubeAPIServer.RequestheaderAllowedNames = []string{"aggregator"}
|
||||
clusterSpec.KubeAPIServer.RequestheaderExtraHeaderPrefixes = []string{"X-Remote-Extra-"}
|
||||
clusterSpec.KubeAPIServer.RequestheaderGroupHeaders = []string{"X-Remote-Group"}
|
||||
clusterSpec.KubeAPIServer.RequestheaderUsernameHeaders = []string{"X-Remote-User"}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,13 +35,25 @@ var _ fi.ModelBuilder = &PKIModelBuilder{}
|
|||
|
||||
// Build is responsible for generating the various pki assets
|
||||
func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||
|
||||
// TODO: Only create the CA via this task
|
||||
defaultCA := &fitasks.Keypair{
|
||||
Name: fi.String(fi.CertificateId_CA),
|
||||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=kubernetes",
|
||||
Type: "ca",
|
||||
}
|
||||
c.AddTask(defaultCA)
|
||||
|
||||
{
|
||||
|
||||
t := &fitasks.Keypair{
|
||||
Name: fi.String("kubelet"),
|
||||
Lifecycle: b.Lifecycle,
|
||||
|
||||
Subject: "o=" + user.NodesGroup + ",cn=kubelet",
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
@ -54,6 +66,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=kubelet-api",
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
})
|
||||
}
|
||||
{
|
||||
|
|
@ -62,6 +75,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=" + user.KubeScheduler,
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
@ -72,6 +86,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=" + user.KubeProxy,
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
@ -82,6 +97,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=" + user.KubeControllerManager,
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
@ -101,6 +117,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Name: fi.String("etcd"),
|
||||
Subject: "cn=etcd",
|
||||
Type: "server",
|
||||
Signer: defaultCA,
|
||||
})
|
||||
}
|
||||
{
|
||||
|
|
@ -109,6 +126,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=etcd-client",
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +136,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Name: fi.String("kube-router"),
|
||||
Subject: "cn=" + "system:kube-router",
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
@ -128,6 +147,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
Subject: "o=" + user.SystemPrivilegedGroup + ",cn=kubecfg",
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
@ -138,16 +158,38 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=apiserver-proxy-client",
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
||||
{
|
||||
aggregatorCA := &fitasks.Keypair{
|
||||
Name: fi.String("apiserver-aggregator-ca"),
|
||||
Lifecycle: b.Lifecycle,
|
||||
Subject: "cn=apiserver-aggregator-ca",
|
||||
Type: "ca",
|
||||
}
|
||||
c.AddTask(aggregatorCA)
|
||||
|
||||
aggregator := &fitasks.Keypair{
|
||||
Name: fi.String("apiserver-aggregator"),
|
||||
Lifecycle: b.Lifecycle,
|
||||
// Must match RequestheaderAllowedNames
|
||||
Subject: "cn=aggregator",
|
||||
Type: "client",
|
||||
Signer: aggregatorCA,
|
||||
}
|
||||
c.AddTask(aggregator)
|
||||
}
|
||||
|
||||
{
|
||||
t := &fitasks.Keypair{
|
||||
Name: fi.String("kops"),
|
||||
Lifecycle: b.Lifecycle,
|
||||
Subject: "o=" + user.SystemPrivilegedGroup + ",cn=kops",
|
||||
Type: "client",
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
@ -183,6 +225,7 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
|||
Subject: "cn=kubernetes-master",
|
||||
Type: "server",
|
||||
AlternateNames: alternateNames,
|
||||
Signer: defaultCA,
|
||||
}
|
||||
c.AddTask(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ func SignNewCertificate(privateKey *PrivateKey, template *x509.Certificate, sign
|
|||
template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
|
||||
}
|
||||
|
||||
if template.ExtKeyUsage == nil {
|
||||
if template.ExtKeyUsage == nil && !template.IsCA {
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||||
}
|
||||
//c.SignatureAlgorithm = do we want to overrride?
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ type Keystore interface {
|
|||
// (if the certificate is found but not keypair, that is not an error: only the cert will be returned)
|
||||
FindKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error)
|
||||
|
||||
CreateKeypair(name string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error)
|
||||
CreateKeypair(signer string, name string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error)
|
||||
|
||||
// StoreKeypair writes the keypair to the store
|
||||
StoreKeypair(id string, cert *pki.Certificate, privateKey *pki.PrivateKey) error
|
||||
|
|
@ -67,11 +67,13 @@ type CAStore interface {
|
|||
Keystore
|
||||
|
||||
// Cert returns the primary specified certificate
|
||||
// For createIfMissing=false, using FindCert is preferred
|
||||
Cert(name string, createIfMissing bool) (*pki.Certificate, error)
|
||||
// CertificatePool returns all active certificates with the specified id
|
||||
CertificatePool(name string, createIfMissing bool) (*CertificatePool, error)
|
||||
PrivateKey(name string, createIfMissing bool) (*pki.PrivateKey, error)
|
||||
|
||||
// FindCert returns the specified certificate, if it exists, or nil if not found
|
||||
FindCert(name string) (*pki.Certificate, error)
|
||||
FindPrivateKey(name string) (*pki.PrivateKey, error)
|
||||
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ type ClientsetCAStore struct {
|
|||
namespace string
|
||||
clientset kopsinternalversion.KopsInterface
|
||||
|
||||
mutex sync.Mutex
|
||||
cacheCaKeyset *keyset
|
||||
mutex sync.Mutex
|
||||
cachedCaKeysets map[string]*keyset
|
||||
}
|
||||
|
||||
var _ CAStore = &ClientsetCAStore{}
|
||||
|
|
@ -51,42 +51,44 @@ var _ CAStore = &ClientsetCAStore{}
|
|||
// NewClientsetCAStore is the constructor for ClientsetCAStore
|
||||
func NewClientsetCAStore(clientset kopsinternalversion.KopsInterface, namespace string) CAStore {
|
||||
c := &ClientsetCAStore{
|
||||
clientset: clientset,
|
||||
namespace: namespace,
|
||||
clientset: clientset,
|
||||
namespace: namespace,
|
||||
cachedCaKeysets: make(map[string]*keyset),
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// readCAKeypairs retrieves the CA keypair, generating a new keypair if not found
|
||||
func (c *ClientsetCAStore) readCAKeypairs() (*keyset, error) {
|
||||
func (c *ClientsetCAStore) readCAKeypairs(id string) (*keyset, error) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
if c.cacheCaKeyset != nil {
|
||||
return c.cacheCaKeyset, nil
|
||||
cached := c.cachedCaKeysets[id]
|
||||
if cached != nil {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
keyset, err := c.loadKeyset(CertificateId_CA)
|
||||
keyset, err := c.loadKeyset(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if keyset == nil {
|
||||
keyset, err = c.generateCACertificate()
|
||||
keyset, err = c.generateCACertificate(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
c.cacheCaKeyset = keyset
|
||||
c.cachedCaKeysets[id] = keyset
|
||||
|
||||
return keyset, nil
|
||||
}
|
||||
|
||||
// generateCACertificate creates and stores a CA keypair
|
||||
// Should be called with the mutex held, to prevent concurrent creation of different keys
|
||||
func (c *ClientsetCAStore) generateCACertificate() (*keyset, error) {
|
||||
func (c *ClientsetCAStore) generateCACertificate(id string) (*keyset, error) {
|
||||
template := BuildCAX509Template()
|
||||
|
||||
caRsaKey, err := rsa.GenerateKey(crypto_rand.Reader, 2048)
|
||||
|
|
@ -104,7 +106,7 @@ func (c *ClientsetCAStore) generateCACertificate() (*keyset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return c.storeAndVerifyKeypair(CertificateId_CA, caCertificate, caPrivateKey)
|
||||
return c.storeAndVerifyKeypair(id, caCertificate, caPrivateKey)
|
||||
}
|
||||
|
||||
// keyset is a parsed Keyset
|
||||
|
|
@ -310,12 +312,12 @@ func (c *ClientsetCAStore) List() ([]*KeystoreItem, error) {
|
|||
}
|
||||
|
||||
// IssueCert implements CAStore::IssueCert
|
||||
func (c *ClientsetCAStore) IssueCert(name string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
func (c *ClientsetCAStore) IssueCert(signer string, name string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
glog.Infof("Issuing new certificate: %q", name)
|
||||
|
||||
template.SerialNumber = serial
|
||||
|
||||
caKeyset, err := c.readCAKeypairs()
|
||||
caKeyset, err := c.readCAKeypairs(signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -416,10 +418,10 @@ func (c *ClientsetCAStore) PrivateKey(name string, createIfMissing bool) (*pki.P
|
|||
}
|
||||
|
||||
// CreateKeypair implements CAStore::CreateKeypair
|
||||
func (c *ClientsetCAStore) CreateKeypair(id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
func (c *ClientsetCAStore) CreateKeypair(signer string, id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
serial := c.buildSerial()
|
||||
|
||||
cert, err := c.IssueCert(id, serial, privateKey, template)
|
||||
cert, err := c.IssueCert(signer, id, serial, privateKey, template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
var wellKnownCertificateTypes = map[string]string{
|
||||
"client": "ExtKeyUsageClientAuth,KeyUsageDigitalSignature",
|
||||
"server": "ExtKeyUsageServerAuth,KeyUsageDigitalSignature,KeyUsageKeyEncipherment",
|
||||
"ca": "CA,KeyUsageCRLSign,KeyUsageCertSign",
|
||||
}
|
||||
|
||||
//go:generate fitask -type=Keypair
|
||||
|
|
@ -41,6 +42,9 @@ type Keypair struct {
|
|||
Type string `json:"type"`
|
||||
AlternateNames []string `json:"alternateNames"`
|
||||
AlternateNameTasks []fi.Task `json:"alternateNameTasks"`
|
||||
|
||||
// Signer is the keypair to use to sign, for when we want to use an alternative CA
|
||||
Signer *Keypair
|
||||
}
|
||||
|
||||
var _ fi.HasCheckExisting = &Keypair{}
|
||||
|
|
@ -51,6 +55,12 @@ func (e *Keypair) CheckExisting(c *fi.Context) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
var _ fi.CompareWithID = &Keypair{}
|
||||
|
||||
func (e *Keypair) CompareWithID() *string {
|
||||
return &e.Subject
|
||||
}
|
||||
|
||||
func (e *Keypair) Find(c *fi.Context) (*Keypair, error) {
|
||||
name := fi.StringValue(e.Name)
|
||||
if name == "" {
|
||||
|
|
@ -84,6 +94,8 @@ func (e *Keypair) Find(c *fi.Context) (*Keypair, error) {
|
|||
Type: buildTypeDescription(cert.Certificate),
|
||||
}
|
||||
|
||||
actual.Signer = &Keypair{Subject: pkixNameToString(&cert.Certificate.Issuer)}
|
||||
|
||||
// Avoid spurious changes
|
||||
actual.Lifecycle = e.Lifecycle
|
||||
|
||||
|
|
@ -133,7 +145,7 @@ func (e *Keypair) normalize(c *fi.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Keypair) CheckChanges(a, e, changes *Keypair) error {
|
||||
func (_ *Keypair) CheckChanges(a, e, changes *Keypair) error {
|
||||
if a != nil {
|
||||
if changes.Name != nil {
|
||||
return fi.CannotChangeField("Name")
|
||||
|
|
@ -184,7 +196,11 @@ func (_ *Keypair) Render(c *fi.Context, a, e, changes *Keypair) error {
|
|||
}
|
||||
}
|
||||
|
||||
cert, err = c.Keystore.CreateKeypair(name, template, privateKey)
|
||||
signer := fi.CertificateId_CA
|
||||
if e.Signer != nil {
|
||||
signer = fi.StringValue(e.Signer.Name)
|
||||
}
|
||||
cert, err = c.Keystore.CreateKeypair(signer, name, template, privateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -256,8 +272,10 @@ func buildCertificateTemplateForType(certificateType string) (*x509.Certificate,
|
|||
return nil, fmt.Errorf("unrecognized certificate option: %v", t)
|
||||
}
|
||||
template.ExtKeyUsage = append(template.ExtKeyUsage, ku)
|
||||
} else if t == "CA" {
|
||||
template.IsCA = true
|
||||
} else {
|
||||
return nil, fmt.Errorf("unrecognized certificate option: %v", t)
|
||||
return nil, fmt.Errorf("unrecognized certificate option: %q", t)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ func NewKubernetesKeystore(client kubernetes.Interface, namespace string) fi.Key
|
|||
return c
|
||||
}
|
||||
|
||||
func (c *KubernetesKeystore) issueCert(id string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
func (c *KubernetesKeystore) issueCert(signer string, id string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
glog.Infof("Issuing new certificate: %q", id)
|
||||
|
||||
template.SerialNumber = serial
|
||||
|
||||
caCert, caKey, err := c.FindKeypair(fi.CertificateId_CA)
|
||||
caCert, caKey, err := c.FindKeypair(signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -107,11 +107,11 @@ func (c *KubernetesKeystore) FindKeypair(id string) (*pki.Certificate, *pki.Priv
|
|||
return keypair.Certificate, keypair.PrivateKey, nil
|
||||
}
|
||||
|
||||
func (c *KubernetesKeystore) CreateKeypair(id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
func (c *KubernetesKeystore) CreateKeypair(signer string, id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
t := time.Now().UnixNano()
|
||||
serial := pki.BuildPKISerial(t)
|
||||
|
||||
cert, err := c.issueCert(id, serial, privateKey, template)
|
||||
cert, err := c.issueCert(signer, id, serial, privateKey, template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,16 +40,21 @@ import (
|
|||
type VFSCAStore struct {
|
||||
basedir vfs.Path
|
||||
|
||||
mutex sync.Mutex
|
||||
cacheCaCertificates *certificates
|
||||
cacheCaPrivateKeys *privateKeys
|
||||
mutex sync.Mutex
|
||||
cachedCAs map[string]*cachedEntry
|
||||
}
|
||||
|
||||
type cachedEntry struct {
|
||||
certificates *certificates
|
||||
privateKeys *privateKeys
|
||||
}
|
||||
|
||||
var _ CAStore = &VFSCAStore{}
|
||||
|
||||
func NewVFSCAStore(basedir vfs.Path) CAStore {
|
||||
c := &VFSCAStore{
|
||||
basedir: basedir,
|
||||
basedir: basedir,
|
||||
cachedCAs: make(map[string]*cachedEntry),
|
||||
}
|
||||
|
||||
return c
|
||||
|
|
@ -60,15 +65,16 @@ func (s *VFSCAStore) VFSPath() vfs.Path {
|
|||
}
|
||||
|
||||
// Retrieves the CA keypair, generating a new keypair if not found
|
||||
func (s *VFSCAStore) readCAKeypairs() (*certificates, *privateKeys, error) {
|
||||
func (s *VFSCAStore) readCAKeypairs(id string) (*certificates, *privateKeys, error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
if s.cacheCaPrivateKeys != nil {
|
||||
return s.cacheCaCertificates, s.cacheCaPrivateKeys, nil
|
||||
cached := s.cachedCAs[id]
|
||||
if cached != nil {
|
||||
return cached.certificates, cached.privateKeys, nil
|
||||
}
|
||||
|
||||
caCertificates, err := s.loadCertificates(s.buildCertificatePoolPath(CertificateId_CA))
|
||||
caCertificates, err := s.loadCertificates(s.buildCertificatePoolPath(id))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -76,7 +82,7 @@ func (s *VFSCAStore) readCAKeypairs() (*certificates, *privateKeys, error) {
|
|||
var caPrivateKeys *privateKeys
|
||||
|
||||
if caCertificates != nil {
|
||||
caPrivateKeys, err = s.loadPrivateKeys(s.buildPrivateKeyPoolPath(CertificateId_CA))
|
||||
caPrivateKeys, err = s.loadPrivateKeys(s.buildPrivateKeyPoolPath(id))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -88,16 +94,16 @@ func (s *VFSCAStore) readCAKeypairs() (*certificates, *privateKeys, error) {
|
|||
}
|
||||
|
||||
if caPrivateKeys == nil {
|
||||
caCertificates, caPrivateKeys, err = s.generateCACertificate()
|
||||
caCertificates, caPrivateKeys, err = s.generateCACertificate(id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
}
|
||||
s.cacheCaCertificates = caCertificates
|
||||
s.cacheCaPrivateKeys = caPrivateKeys
|
||||
cached = &cachedEntry{certificates: caCertificates, privateKeys: caPrivateKeys}
|
||||
s.cachedCAs[id] = cached
|
||||
|
||||
return s.cacheCaCertificates, s.cacheCaPrivateKeys, nil
|
||||
return cached.certificates, cached.privateKeys, nil
|
||||
}
|
||||
|
||||
func BuildCAX509Template() *x509.Certificate {
|
||||
|
|
@ -117,7 +123,7 @@ func BuildCAX509Template() *x509.Certificate {
|
|||
|
||||
// Creates and stores CA keypair
|
||||
// Should be called with the mutex held, to prevent concurrent creation of different keys
|
||||
func (c *VFSCAStore) generateCACertificate() (*certificates, *privateKeys, error) {
|
||||
func (c *VFSCAStore) generateCACertificate(id string) (*certificates, *privateKeys, error) {
|
||||
template := BuildCAX509Template()
|
||||
|
||||
caRsaKey, err := rsa.GenerateKey(crypto_rand.Reader, 2048)
|
||||
|
|
@ -135,14 +141,14 @@ func (c *VFSCAStore) generateCACertificate() (*certificates, *privateKeys, error
|
|||
t := time.Now().UnixNano()
|
||||
serial := pki.BuildPKISerial(t)
|
||||
|
||||
keyPath := c.buildPrivateKeyPath(CertificateId_CA, serial)
|
||||
keyPath := c.buildPrivateKeyPath(id, serial)
|
||||
err = c.storePrivateKey(caPrivateKey, keyPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Make double-sure it round-trips
|
||||
privateKeys, err := c.loadPrivateKeys(c.buildPrivateKeyPoolPath(CertificateId_CA))
|
||||
privateKeys, err := c.loadPrivateKeys(c.buildPrivateKeyPoolPath(id))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -150,14 +156,14 @@ func (c *VFSCAStore) generateCACertificate() (*certificates, *privateKeys, error
|
|||
return nil, nil, fmt.Errorf("failed to round-trip CA private key")
|
||||
}
|
||||
|
||||
certPath := c.buildCertificatePath(CertificateId_CA, serial)
|
||||
certPath := c.buildCertificatePath(id, serial)
|
||||
err = c.storeCertificate(caCertificate, certPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Make double-sure it round-trips
|
||||
certificates, err := c.loadCertificates(c.buildCertificatePoolPath(CertificateId_CA))
|
||||
certificates, err := c.loadCertificates(c.buildCertificatePoolPath(id))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -414,25 +420,34 @@ func (c *VFSCAStore) MirrorTo(basedir vfs.Path) error {
|
|||
return vfs.CopyTree(c.basedir, basedir)
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
func (c *VFSCAStore) IssueCert(signer string, id string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
glog.Infof("Issuing new certificate: %q", id)
|
||||
|
||||
template.SerialNumber = serial
|
||||
|
||||
caCertificates, caPrivateKeys, err := c.readCAKeypairs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var cert *pki.Certificate
|
||||
if template.IsCA {
|
||||
var err error
|
||||
cert, err = pki.SignNewCertificate(privateKey, template, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
caCertificates, caPrivateKeys, err := c.readCAKeypairs(signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if caPrivateKeys == nil || caPrivateKeys.Primary() == nil {
|
||||
return nil, fmt.Errorf("ca key for %q was not found; cannot issue certificates", signer)
|
||||
}
|
||||
cert, err = pki.SignNewCertificate(privateKey, template, caCertificates.Primary().Certificate, caPrivateKeys.Primary())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if caPrivateKeys == nil || caPrivateKeys.Primary() == nil {
|
||||
return nil, fmt.Errorf("ca.key was not found; cannot issue certificates")
|
||||
}
|
||||
cert, err := pki.SignNewCertificate(privateKey, template, caCertificates.Primary().Certificate, caPrivateKeys.Primary())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.StoreKeypair(id, cert, privateKey)
|
||||
err := c.StoreKeypair(id, cert, privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -557,7 +572,7 @@ func (c *VFSCAStore) loadOnePrivateKey(p vfs.Path) (*pki.PrivateKey, error) {
|
|||
func (c *VFSCAStore) FindPrivateKey(id string) (*pki.PrivateKey, error) {
|
||||
var keys *privateKeys
|
||||
if id == CertificateId_CA {
|
||||
_, caPrivateKeys, err := c.readCAKeypairs()
|
||||
_, caPrivateKeys, err := c.readCAKeypairs(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -592,10 +607,10 @@ func (c *VFSCAStore) PrivateKey(id string, createIfMissing bool) (*pki.PrivateKe
|
|||
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) CreateKeypair(id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
func (c *VFSCAStore) CreateKeypair(signer string, id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
serial := c.buildSerial()
|
||||
|
||||
cert, err := c.IssueCert(id, serial, privateKey, template)
|
||||
cert, err := c.IssueCert(signer, id, serial, privateKey, template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue