forked from libopenstorage/stork
/
utils.go
153 lines (140 loc) · 4.42 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package webhookadmission
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"time"
"github.com/portworx/sched-ops/k8s/admissionregistration"
"github.com/portworx/sched-ops/k8s/core"
log "github.com/sirupsen/logrus"
admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1"
v1 "k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
webhookName = "webhook.stork.libopenstorage.org"
storkService = "stork-service"
storkNamespaceEnv = "STORK-NAMESPACE"
defaultNamespace = "kube-system"
)
// CreateMutateWebhook create new webhookconfig for stork if not exist already
func CreateMutateWebhook(caBundle []byte, ns string) error {
path := "/mutate"
// We make best efforts to change incoming apps scheduler to stork, if application is
// using stork supported storage drivers.
sideEffect := admissionv1beta1.SideEffectClassNoneOnDryRun
webhook := admissionv1beta1.MutatingWebhook{
Name: webhookName,
ClientConfig: admissionv1beta1.WebhookClientConfig{
Service: &admissionv1beta1.ServiceReference{
Name: storkService,
Namespace: ns,
Path: &path,
},
CABundle: caBundle,
},
Rules: []admissionv1beta1.RuleWithOperations{
{
Operations: []admissionv1beta1.OperationType{admissionv1beta1.Create},
Rule: admissionv1beta1.Rule{
APIGroups: []string{"apps", ""},
APIVersions: []string{"v1"},
Resources: []string{"deployments", "statefulsets", "pods"},
},
},
},
SideEffects: &sideEffect,
}
req := &admissionv1beta1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: storkAdmissionController,
},
Webhooks: []admissionv1beta1.MutatingWebhook{webhook},
}
resp, err := admissionregistration.Instance().GetMutatingWebhookConfiguration(storkAdmissionController)
if err != nil {
if k8serr.IsNotFound(err) {
_, err = admissionregistration.Instance().CreateMutatingWebhookConfiguration(req)
}
return err
}
req.ResourceVersion = resp.ResourceVersion
if _, err := admissionregistration.Instance().UpdateMutatingWebhookConfiguration(req); err != nil {
log.Errorf("unable to update webhook configuration: %v", err)
return err
}
log.Debugf("stork webhook configured: %v", webhookName)
return nil
}
// GenerateCertificate Self Signed certificate using given CN, returns x509 cert
// and priv key in PEM format
func GenerateCertificate(cn string) ([]byte, []byte, error) {
var err error
pemCert := &bytes.Buffer{}
// generate private key
priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
if err != nil {
log.Errorf("error generating crypt keys: %v", err)
return nil, nil, err
}
// create certificate
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: cn,
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IsCA: true,
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
log.Errorf("Failed to create x509 certificate: %s", err)
return nil, nil, err
}
err = pem.Encode(pemCert, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
if err != nil {
log.Errorf("Unable to encode x509 certificate to PEM format: %v", err)
return nil, nil, err
}
b, err := x509.MarshalECPrivateKey(priv)
if err != nil {
log.Errorf("Unable to marshal ECDSA private key: %v", err)
return nil, nil, err
}
privBlock := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: b,
}
return pemCert.Bytes(), pem.EncodeToMemory(&privBlock), nil
}
// GetTLSCertificate from pub and priv key
func GetTLSCertificate(cert, priv []byte) (tls.Certificate, error) {
return tls.X509KeyPair(cert, priv)
}
// CreateCertSecrets creates k8s secret to store self signed cert
// data
func CreateCertSecrets(cert, key []byte, ns string) (*v1.Secret, error) {
secretData := make(map[string][]byte)
secretData[privKey] = key
secretData[privCert] = cert
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: ns,
},
Data: secretData,
}
return core.Instance().CreateSecret(secret)
}