mirror of https://github.com/kubernetes/kops.git
Rework keypair to fit our change model
We also remove another special-case context (pki), so that it is just another object type.
This commit is contained in:
parent
ac220d2ba1
commit
1c97a94d87
|
@ -12,6 +12,7 @@ import (
|
|||
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/gce"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/gcetasks"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/terraform"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/fitasks"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/loader"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/utils"
|
||||
"os"
|
||||
|
@ -154,6 +155,10 @@ func (c *CreateClusterCmd) Run() error {
|
|||
|
||||
c.Config.NodeUpTags = append(c.Config.NodeUpTags, "_jessie", "_debian_family", "_systemd")
|
||||
|
||||
l.AddTypes(map[string]interface{}{
|
||||
"keypair": &fitasks.Keypair{},
|
||||
})
|
||||
|
||||
switch c.Config.CloudProvider {
|
||||
case "gce":
|
||||
{
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
subject:
|
||||
CommonName: kubecfg
|
||||
type: client
|
||||
keypair/kubecfg:
|
||||
subject: cn=kubecfg
|
||||
type: client
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
subject:
|
||||
CommonName: kubelet
|
||||
type: client
|
||||
keypair/kubelet:
|
||||
subject: cn=kubelet
|
||||
type: client
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
subject:
|
||||
CommonName: kubernetes-master
|
||||
type: server
|
||||
alternateNames:
|
||||
- kubernetes
|
||||
- kubernetes.default
|
||||
- kubernetes.default.svc
|
||||
- kubernetes.default.svc.{{ .DNSDomain }}
|
||||
- {{ .MasterName }}
|
||||
- {{ .MasterPublicIP }}
|
||||
- {{ .MasterInternalIP }}
|
||||
- {{ .WellKnownServiceIP 1 }}
|
||||
keypair/master:
|
||||
subject: cn=kubernetes-master
|
||||
type: server
|
||||
alternateNames:
|
||||
- kubernetes
|
||||
- kubernetes.default
|
||||
- kubernetes.default.svc
|
||||
- kubernetes.default.svc.{{ .DNSDomain }}
|
||||
- "{{ .MasterName }}"
|
||||
- "{{ .MasterInternalIP }}"
|
||||
- "{{ .WellKnownServiceIP 1 }}"
|
||||
- "{{ .MasterPublicIP }}"
|
||||
{{ if eq .CloudProvider "aws" }}
|
||||
alternateNameTasks:
|
||||
- elasticIP/{{ .MasterName }}-ip
|
||||
{{ else if eq .CloudProvider "gce" }}
|
||||
alternateNameTasks:
|
||||
- ipAddress/{{ .MasterName }}-ip
|
||||
{{ end }}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/golang/glog"
|
||||
"io"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/fitasks"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/loader"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/nodeup"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/utils"
|
||||
|
@ -129,6 +128,8 @@ func (l *Loader) executeTemplate(key string, d string, args []string) (string, e
|
|||
}
|
||||
t.Funcs(funcMap)
|
||||
|
||||
t.Option("missingkey=zero")
|
||||
|
||||
context := l.config
|
||||
|
||||
_, err := t.Parse(d)
|
||||
|
@ -136,8 +137,6 @@ func (l *Loader) executeTemplate(key string, d string, args []string) (string, e
|
|||
return "", fmt.Errorf("error parsing template %q: %v", key, err)
|
||||
}
|
||||
|
||||
t.Option("missingkey=zero")
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err = t.ExecuteTemplate(&buffer, key, context)
|
||||
if err != nil {
|
||||
|
@ -157,7 +156,6 @@ func (l *Loader) Build(baseDir string) (map[string]fi.Task, error) {
|
|||
DefaultHandler: ignoreHandler,
|
||||
Contexts: map[string]loader.Handler{
|
||||
"resources": ignoreHandler,
|
||||
"pki": ignoreHandler,
|
||||
},
|
||||
Extensions: map[string]loader.Handler{
|
||||
".options": l.OptionsLoader.HandleOptions,
|
||||
|
@ -180,7 +178,6 @@ func (l *Loader) Build(baseDir string) (map[string]fi.Task, error) {
|
|||
DefaultHandler: l.objectHandler,
|
||||
Contexts: map[string]loader.Handler{
|
||||
"resources": l.resourceHandler,
|
||||
"pki": l.pkiHandler,
|
||||
},
|
||||
Extensions: map[string]loader.Handler{
|
||||
".options": ignoreHandler,
|
||||
|
@ -285,27 +282,6 @@ func (l *Loader) resourceHandler(i *loader.TreeWalkItem) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (l *Loader) pkiHandler(i *loader.TreeWalkItem) error {
|
||||
contents, err := i.ReadString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := i.RelativePath
|
||||
|
||||
contents, err = l.executeTemplate(key, contents, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
task, err := fitasks.NewPKIKeyPairTask(key, contents, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.tasks["pki/"+i.RelativePath] = task
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Loader) objectHandler(i *loader.TreeWalkItem) error {
|
||||
contents, err := i.ReadString()
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
package fitasks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func pkixNameToString(name *pkix.Name) string {
|
||||
seq := name.ToRDNSequence()
|
||||
var s bytes.Buffer
|
||||
for _, rdnSet := range seq {
|
||||
for _, rdn := range rdnSet {
|
||||
if s.Len() != 0 {
|
||||
s.WriteString(",")
|
||||
}
|
||||
key := ""
|
||||
t := rdn.Type
|
||||
if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
|
||||
switch t[3] {
|
||||
case 3:
|
||||
key = "cn"
|
||||
case 5:
|
||||
key = "serial"
|
||||
case 6:
|
||||
key = "c"
|
||||
case 7:
|
||||
key = "l"
|
||||
case 10:
|
||||
key = "o"
|
||||
case 11:
|
||||
key = "ou"
|
||||
}
|
||||
}
|
||||
if key == "" {
|
||||
key = t.String()
|
||||
}
|
||||
s.WriteString(fmt.Sprintf("%v=%v", key, rdn.Value))
|
||||
}
|
||||
}
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func parsePkixName(s string) (*pkix.Name, error) {
|
||||
name := new(pkix.Name)
|
||||
|
||||
tokens := strings.Split(s, ",")
|
||||
for _, token := range tokens {
|
||||
token = strings.TrimSpace(token)
|
||||
kv := strings.SplitN(token, "=", 2)
|
||||
if len(kv) != 2 {
|
||||
return nil, fmt.Errorf("unrecognized token (expected k=v): %q", token)
|
||||
}
|
||||
k := strings.ToLower(kv[0])
|
||||
v := kv[1]
|
||||
|
||||
switch k {
|
||||
case "cn":
|
||||
name.CommonName = v
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized key %q in token %q", k, token)
|
||||
}
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
var keyUsageStrings = map[x509.KeyUsage]string{
|
||||
x509.KeyUsageDigitalSignature: "KeyUsageDigitalSignature",
|
||||
x509.KeyUsageContentCommitment: "KeyUsageContentCommitment",
|
||||
x509.KeyUsageKeyEncipherment: "KeyUsageKeyEncipherment",
|
||||
x509.KeyUsageDataEncipherment: "KeyUsageDataEncipherment",
|
||||
x509.KeyUsageKeyAgreement: "KeyUsageKeyAgreement",
|
||||
x509.KeyUsageCertSign: "KeyUsageCertSign",
|
||||
x509.KeyUsageCRLSign: "KeyUsageCRLSign",
|
||||
x509.KeyUsageEncipherOnly: "KeyUsageEncipherOnly",
|
||||
x509.KeyUsageDecipherOnly: "KeyUsageDecipherOnly",
|
||||
}
|
||||
|
||||
func keyUsageToString(u x509.KeyUsage) []string {
|
||||
var usages []string
|
||||
|
||||
for k, v := range keyUsageStrings {
|
||||
if (u & k) != 0 {
|
||||
usages = append(usages, v)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Detect if there are other flags set?
|
||||
return usages
|
||||
}
|
||||
|
||||
func parseKeyUsage(s string) (x509.KeyUsage, bool) {
|
||||
for k, v := range keyUsageStrings {
|
||||
if v == s {
|
||||
return k, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
var extKeyUsageStrings = map[x509.ExtKeyUsage]string{
|
||||
x509.ExtKeyUsageAny: "ExtKeyUsageAny",
|
||||
x509.ExtKeyUsageServerAuth: "ExtKeyUsageServerAuth",
|
||||
x509.ExtKeyUsageClientAuth: "ExtKeyUsageClientAuth",
|
||||
x509.ExtKeyUsageCodeSigning: "ExtKeyUsageCodeSigning",
|
||||
x509.ExtKeyUsageEmailProtection: "ExtKeyUsageEmailProtection",
|
||||
x509.ExtKeyUsageIPSECEndSystem: "ExtKeyUsageIPSECEndSystem",
|
||||
x509.ExtKeyUsageIPSECTunnel: "ExtKeyUsageIPSECTunnel",
|
||||
x509.ExtKeyUsageIPSECUser: "ExtKeyUsageIPSECUser",
|
||||
x509.ExtKeyUsageTimeStamping: "ExtKeyUsageTimeStamping",
|
||||
x509.ExtKeyUsageOCSPSigning: "ExtKeyUsageOCSPSigning",
|
||||
x509.ExtKeyUsageMicrosoftServerGatedCrypto: "ExtKeyUsageMicrosoftServerGatedCrypto",
|
||||
x509.ExtKeyUsageNetscapeServerGatedCrypto: "ExtKeyUsageNetscapeServerGatedCrypto",
|
||||
}
|
||||
|
||||
func extKeyUsageToString(u x509.ExtKeyUsage) string {
|
||||
s := extKeyUsageStrings[u]
|
||||
if s == "" {
|
||||
glog.Warningf("Unhandled ExtKeyUsage: %v", u)
|
||||
s = fmt.Sprintf("ExtKeyUsage:%v", u)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func parseExtKeyUsage(s string) (x509.ExtKeyUsage, bool) {
|
||||
for k, v := range extKeyUsageStrings {
|
||||
if v == s {
|
||||
return k, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
package fitasks
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var wellKnownCertificateTypes = map[string]string{
|
||||
"client": "ExtKeyUsageClientAuth,KeyUsageDigitalSignature",
|
||||
"server": "ExtKeyUsageServerAuth,KeyUsageDigitalSignature,KeyUsageKeyEncipherment",
|
||||
}
|
||||
|
||||
type Keypair struct {
|
||||
Name string
|
||||
Subject string `json:"subject"`
|
||||
Type string `json:"type"`
|
||||
AlternateNames []string `json:"alternateNames"`
|
||||
AlternateNameTasks []fi.Task `json:"alternateNameTasks"`
|
||||
}
|
||||
|
||||
func (e *Keypair) String() string {
|
||||
return fi.TaskAsString(e)
|
||||
}
|
||||
|
||||
func (e *Keypair) Find(c *fi.Context) (*Keypair, error) {
|
||||
castore := c.CAStore
|
||||
cert, err := castore.FindCert(e.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cert == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
key, err := castore.FindPrivateKey(e.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key == nil {
|
||||
return nil, fmt.Errorf("found cert in store, but did not find private key: %q", e.Name)
|
||||
}
|
||||
|
||||
var alternateNames []string
|
||||
alternateNames = append(alternateNames, cert.Certificate.DNSNames...)
|
||||
alternateNames = append(alternateNames, cert.Certificate.EmailAddresses...)
|
||||
for _, ip := range cert.Certificate.IPAddresses {
|
||||
alternateNames = append(alternateNames, ip.String())
|
||||
}
|
||||
sort.Strings(alternateNames)
|
||||
|
||||
actual := &Keypair{
|
||||
Name: e.Name,
|
||||
Subject: pkixNameToString(&cert.Subject),
|
||||
AlternateNames: alternateNames,
|
||||
Type: buildTypeDescription(cert.Certificate),
|
||||
}
|
||||
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
func (e *Keypair) Run(c *fi.Context) error {
|
||||
err := e.normalize(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fi.DefaultDeltaRunMethod(e, c)
|
||||
}
|
||||
|
||||
func (e *Keypair) normalize(c *fi.Context) error {
|
||||
var alternateNames []string
|
||||
|
||||
for _, s := range e.AlternateNames {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
alternateNames = append(alternateNames, s)
|
||||
}
|
||||
|
||||
for _, task := range e.AlternateNameTasks {
|
||||
if hasAddress, ok := task.(fi.HasAddress); ok {
|
||||
address, err := hasAddress.FindAddress(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding address for %v: %v", task, err)
|
||||
}
|
||||
if address == nil {
|
||||
glog.Warningf("Task did not have an address: %v", task)
|
||||
continue
|
||||
}
|
||||
glog.V(8).Infof("Resolved alternateName %q for %q", *address, task)
|
||||
alternateNames = append(alternateNames, *address)
|
||||
} else {
|
||||
return fmt.Errorf("Unsupported type for AlternateNameDependencies: %v", task)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(alternateNames)
|
||||
e.AlternateNames = alternateNames
|
||||
e.AlternateNameTasks = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Keypair) CheckChanges(a, e, changes *Keypair) error {
|
||||
if a != nil {
|
||||
if changes.Name != "" {
|
||||
return fi.CannotChangeField("Name")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Keypair) Render(c *fi.Context, a, e, changes *Keypair) error {
|
||||
castore := c.CAStore
|
||||
|
||||
template, err := buildCertificateTempate(e.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subjectPkix, err := parsePkixName(e.Subject)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing Subject: %v", err)
|
||||
}
|
||||
|
||||
if len(subjectPkix.ToRDNSequence()) == 0 {
|
||||
return fmt.Errorf("Subject name was empty for SSL keypair %q", e.Name)
|
||||
}
|
||||
|
||||
template.Subject = *subjectPkix
|
||||
|
||||
var alternateNames []string
|
||||
alternateNames = append(alternateNames, e.AlternateNames...)
|
||||
|
||||
for _, san := range alternateNames {
|
||||
san = strings.TrimSpace(san)
|
||||
if san == "" {
|
||||
continue
|
||||
}
|
||||
if ip := net.ParseIP(san); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, san)
|
||||
}
|
||||
}
|
||||
|
||||
createCertificate := false
|
||||
if a == nil {
|
||||
createCertificate = true
|
||||
} else if changes != nil {
|
||||
if changes.AlternateNames != nil {
|
||||
createCertificate = true
|
||||
} else {
|
||||
glog.Warningf("Ignoring changes in key: %v", fi.DebugAsJsonString(changes))
|
||||
}
|
||||
}
|
||||
|
||||
if createCertificate {
|
||||
glog.V(2).Infof("Creating PKI keypair %q", e.Name)
|
||||
|
||||
// TODO: Reuse private key if already exists?
|
||||
privateKey, err := castore.CreatePrivateKey(e.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cert, err := castore.IssueCert(e.Name, privateKey, template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(8).Infof("created certificate %v", cert)
|
||||
}
|
||||
|
||||
// TODO: Check correct subject / flags
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildCertificateTempate(certificateType string) (*x509.Certificate, error) {
|
||||
if expanded, found := wellKnownCertificateTypes[certificateType]; found {
|
||||
certificateType = expanded
|
||||
}
|
||||
|
||||
template := &x509.Certificate{
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: false,
|
||||
}
|
||||
|
||||
tokens := strings.Split(certificateType, ",")
|
||||
for _, t := range tokens {
|
||||
if strings.HasPrefix(t, "KeyUsage") {
|
||||
ku, found := parseKeyUsage(t)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("unrecognized certificate option: %v", t)
|
||||
}
|
||||
template.KeyUsage |= ku
|
||||
} else if strings.HasPrefix(t, "ExtKeyUsage") {
|
||||
ku, found := parseExtKeyUsage(t)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("unrecognized certificate option: %v", t)
|
||||
}
|
||||
template.ExtKeyUsage = append(template.ExtKeyUsage, ku)
|
||||
} else {
|
||||
return nil, fmt.Errorf("unrecognized certificate option: %v", t)
|
||||
}
|
||||
}
|
||||
|
||||
return template, nil
|
||||
}
|
||||
|
||||
func buildTypeDescription(cert *x509.Certificate) string {
|
||||
var options []string
|
||||
|
||||
if cert.IsCA {
|
||||
options = append(options, "CA")
|
||||
}
|
||||
|
||||
options = append(options, keyUsageToString(cert.KeyUsage)...)
|
||||
|
||||
for _, extKeyUsage := range cert.ExtKeyUsage {
|
||||
options = append(options, extKeyUsageToString(extKeyUsage))
|
||||
}
|
||||
|
||||
sort.Strings(options)
|
||||
s := strings.Join(options, ",")
|
||||
|
||||
for k, v := range wellKnownCertificateTypes {
|
||||
if v == s {
|
||||
s = k
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package fitasks
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi"
|
||||
"k8s.io/kube-deploy/upup/pkg/fi/utils"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CertificateType_Client string = "client"
|
||||
CertificateType_Server string = "server"
|
||||
)
|
||||
|
||||
type PKIKeyPairTask struct {
|
||||
Name string
|
||||
Subject *pkix.Name `json:"subject"`
|
||||
Type string `json:"type"`
|
||||
AlternateNames []string `json:"alternateNames"`
|
||||
}
|
||||
|
||||
func (t *PKIKeyPairTask) String() string {
|
||||
return fmt.Sprintf("PKI: %s", t.Name)
|
||||
}
|
||||
|
||||
func NewPKIKeyPairTask(name string, contents string, meta string) (fi.Task, error) {
|
||||
t := &PKIKeyPairTask{Name: name}
|
||||
|
||||
if contents != "" {
|
||||
err := utils.YamlUnmarshal([]byte(contents), t)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing data for PKIKeyPairTask %q: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if meta != "" {
|
||||
return nil, fmt.Errorf("meta is not supported for PKIKeyPairTask")
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *PKIKeyPairTask) Run(c *fi.Context) error {
|
||||
castore := c.CAStore
|
||||
cert, err := castore.FindCert(t.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cert != nil {
|
||||
key, err := castore.FindPrivateKey(t.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if key == nil {
|
||||
return fmt.Errorf("found cert in store, but did not find keypair: %q", t.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if cert == nil {
|
||||
glog.V(2).Infof("Creating PKI keypair %q", t.Name)
|
||||
|
||||
template := &x509.Certificate{
|
||||
Subject: *t.Subject,
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: false,
|
||||
}
|
||||
|
||||
if len(t.Subject.ToRDNSequence()) == 0 {
|
||||
return fmt.Errorf("Subject name was empty for SSL keypair %q", t.Name)
|
||||
}
|
||||
|
||||
switch t.Type {
|
||||
case CertificateType_Client:
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
|
||||
template.KeyUsage = x509.KeyUsageDigitalSignature
|
||||
break
|
||||
|
||||
case CertificateType_Server:
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||||
template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
|
||||
break
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown certificate type: %q", t.Type)
|
||||
}
|
||||
|
||||
for _, san := range t.AlternateNames {
|
||||
san = strings.TrimSpace(san)
|
||||
if san == "" {
|
||||
continue
|
||||
}
|
||||
if ip := net.ParseIP(san); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, san)
|
||||
}
|
||||
}
|
||||
|
||||
privateKey, err := castore.CreatePrivateKey(t.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cert, err = castore.IssueCert(t.Name, privateKey, template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check correct subject / flags
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue