-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SRIOV provider, csrcreator: switch to self-sign certificates (#472)
* sriov provider, cert generator: switch to self-sign certificates Currently we use Kubernetes CertificateSigningRequest (CSR) for creating certificats for sriov-network-operaotor webhhoks. We encounter flakiness on during CSR negotiation causing cluster-up to fail often. This commit presents new code for generating self-signed certificats for sriov-network-operator webhooks. Signed-off-by: Or Mergi <[email protected]> * update .gitigone Signed-off-by: Or Mergi <[email protected]>
- Loading branch information
Showing
7 changed files
with
268 additions
and
259 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
cluster/kind-k8s-sriov*/csrcreator/*.cert | ||
cluster/kind-k8s-sriov*/certcreator/*.cert |
115 changes: 115 additions & 0 deletions
115
cluster-up/cluster/kind-k8s-sriov-1.17.0/certcreator/certlib/selfsign.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package certlib | ||
|
||
import ( | ||
"bytes" | ||
cryptorand "crypto/rand" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/pem" | ||
"fmt" | ||
"math/big" | ||
"math/rand" | ||
"time" | ||
) | ||
|
||
type SelfSignedCertificate struct { | ||
DNSNames []string | ||
CommonName string | ||
Certificate *bytes.Buffer | ||
PrivateKey *bytes.Buffer | ||
} | ||
|
||
func (s *SelfSignedCertificate) Generate() error { | ||
var caPEM *bytes.Buffer | ||
|
||
randomSource := rand.New(rand.NewSource(time.Now().Unix())) | ||
caCertificateConfig := &x509.Certificate{ | ||
SerialNumber: big.NewInt(randomSource.Int63()), | ||
Subject: pkix.Name{ | ||
Organization: []string{"kubvirt.io"}, | ||
}, | ||
NotBefore: time.Now(), | ||
NotAfter: time.Now().AddDate(1, 0, 0), | ||
IsCA: true, | ||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, | ||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, | ||
BasicConstraintsValid: true, | ||
} | ||
|
||
caPrivateKey, err := rsa.GenerateKey(cryptorand.Reader, 4096) | ||
if err != nil { | ||
return fmt.Errorf("failed to generate CA private key: %v", err) | ||
} | ||
|
||
caSelfSignedCertificateBytes, err := x509.CreateCertificate( | ||
cryptorand.Reader, | ||
caCertificateConfig, | ||
caCertificateConfig, | ||
&caPrivateKey.PublicKey, | ||
caPrivateKey) | ||
if err != nil { | ||
return fmt.Errorf("failed to generate CA certificate: %v", err) | ||
} | ||
|
||
// PEM encode CA cert | ||
caPEM = new(bytes.Buffer) | ||
err = pem.Encode(caPEM, &pem.Block{ | ||
Type: "CERTIFICATE", | ||
Bytes: caSelfSignedCertificateBytes, | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("failed to encode CA certificate bytes to PEM: %v", err) | ||
} | ||
|
||
serverCertificateConfig := &x509.Certificate{ | ||
DNSNames: s.DNSNames, | ||
SerialNumber: big.NewInt(randomSource.Int63()), | ||
Subject: pkix.Name{ | ||
CommonName: s.CommonName, | ||
Organization: []string{"kubevirt.io"}, | ||
}, | ||
NotBefore: time.Now(), | ||
NotAfter: time.Now().AddDate(1, 0, 0), | ||
SubjectKeyId: []byte{1, 2, 3, 4, 6}, | ||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, | ||
KeyUsage: x509.KeyUsageDigitalSignature, | ||
} | ||
|
||
serverPrivateKey, err := rsa.GenerateKey(cryptorand.Reader, 4096) | ||
if err != nil { | ||
return fmt.Errorf("failed to generate server private key: %v", err) | ||
} | ||
|
||
// Signing server certificate | ||
serverCertificateBytes, err := x509.CreateCertificate( | ||
cryptorand.Reader, | ||
serverCertificateConfig, | ||
caCertificateConfig, | ||
&serverPrivateKey.PublicKey, | ||
caPrivateKey) | ||
if err != nil { | ||
return fmt.Errorf("failed to sign server certificate: %v", err) | ||
} | ||
|
||
// PEM encode the server cert and key | ||
s.Certificate = new(bytes.Buffer) | ||
err = pem.Encode(s.Certificate, &pem.Block{ | ||
Type: "CERTIFICATE", | ||
Bytes: serverCertificateBytes, | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("failed to encode server certificate bytes to PEM: %v", err) | ||
} | ||
|
||
s.PrivateKey = new(bytes.Buffer) | ||
err = pem.Encode(s.PrivateKey, &pem.Block{ | ||
Type: "RSA PRIVATE KEY", | ||
Bytes: x509.MarshalPKCS1PrivateKey(serverPrivateKey), | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("failed to encode server private key bytes to PEM: %v", err) | ||
} | ||
|
||
return nil | ||
} |
140 changes: 140 additions & 0 deletions
140
cluster-up/cluster/kind-k8s-sriov-1.17.0/certcreator/certsecret.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/base64" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/util/wait" | ||
"k8s.io/client-go/kubernetes" | ||
"k8s.io/client-go/rest" | ||
"k8s.io/client-go/tools/clientcmd" | ||
|
||
"kubevirt.io/kubevirtci/cluster-up/cluster/kind-k8s-sriov-1.17.0/certcreator/certlib" | ||
) | ||
|
||
func handleKubeClientConfig(kubeconfig string) (*rest.Config, error) { | ||
if kubeconfig == "" { | ||
log.Printf("Using env kubeconfig %s", kubeconfig) | ||
kubeconfig = os.Getenv("KUBECONFIG") | ||
} | ||
|
||
var config *rest.Config | ||
var err error | ||
if kubeconfig != "" { | ||
log.Printf("Loading kube client config from path %q", kubeconfig) | ||
config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) | ||
} else { | ||
log.Printf("Using in-cluster kube client config") | ||
config, err = rest.InClusterConfig() | ||
} | ||
if err != nil { | ||
return nil, fmt.Errorf("could not get the client: %v", err) | ||
} | ||
|
||
return config, nil | ||
} | ||
|
||
func generate(hookName, namespace string) ([]byte, []byte, error) { | ||
serviceName := strings.Join([]string{hookName, "service"}, "-") | ||
|
||
certConfig := certlib.SelfSignedCertificate{ | ||
CommonName: strings.Join([]string{serviceName, namespace, "svc"}, "."), | ||
DNSNames: []string{ | ||
serviceName, | ||
strings.Join([]string{serviceName, namespace}, "."), | ||
strings.Join([]string{serviceName, namespace, "svc"}, ".")}, | ||
} | ||
err := certConfig.Generate() | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to generate self-signed certificate: %v", err) | ||
} | ||
log.Printf("Self-Signed certificate created sucessfully for CN %s", certConfig.CommonName) | ||
|
||
return certConfig.Certificate.Bytes(), certConfig.PrivateKey.Bytes(), nil | ||
} | ||
|
||
func exportCertificateFile(data []byte, filePath string) error { | ||
certificateFileName := fmt.Sprintf("%s.cert", filePath) | ||
encodedData := []byte(base64.StdEncoding.EncodeToString(data)) | ||
if err := ioutil.WriteFile(certificateFileName, encodedData, 0644); err != nil { | ||
return fmt.Errorf("failed to write content to file %s: %v", filePath, err) | ||
} | ||
log.Printf("certificate exported successfully to: %s", filePath) | ||
|
||
return nil | ||
} | ||
|
||
func createSecret(clusterApi kubernetes.Interface, namespace, secretName string, certificate, key []byte) error { | ||
secret := &corev1.Secret{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: secretName, | ||
Namespace: namespace, | ||
}, | ||
Data: map[string][]byte{ | ||
"tls.crt": certificate, | ||
"tls.key": key, | ||
}, | ||
} | ||
|
||
err := wait.Poll(time.Second*5, time.Minute*3, func() (bool, error) { | ||
_, err := clusterApi.CoreV1().Secrets(namespace).Create(secret) | ||
if err != nil { | ||
log.Printf("failed to create secret '%s': %v", secret.Name, err) | ||
return false, nil | ||
} | ||
return true, nil | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("timeout waiting for secret '%s' to create secret: %v", secret.Name, err) | ||
} | ||
log.Printf("Secret '%s' at '%s' created sucessfully", secret.Name, namespace) | ||
|
||
return nil | ||
} | ||
|
||
func main() { | ||
namespace := flag.String("namespace", "", "The namespace of the webhook") | ||
kubeconfig := flag.String("kubeconfig", "", "The path of kubeconfig") | ||
hookName := flag.String("hook", "", "The name of the hook") | ||
secretName := flag.String("secret", "", "The name of the secret") | ||
flag.Parse() | ||
|
||
if *namespace == "" || *hookName == "" || *secretName == "" { | ||
flag.Usage() | ||
log.Fatal("Not enough arguments") | ||
} | ||
|
||
var err error | ||
config, err := handleKubeClientConfig(*kubeconfig) | ||
if err != nil { | ||
log.Fatalf("Failed to set kubernetes client config: %v", err) | ||
} | ||
|
||
clientset, err := kubernetes.NewForConfig(config) | ||
if err != nil { | ||
log.Fatalf("Failed to set up Kubernetes client: %v", err) | ||
} | ||
|
||
certificate, key, err := generate(*hookName, *namespace) | ||
if err != nil { | ||
log.Fatalf("Failed to generate certificate: %v", err) | ||
} | ||
|
||
err = exportCertificateFile(certificate, *hookName) | ||
if err != nil { | ||
log.Fatalf("Failed to export certificate to file: %v", err) | ||
} | ||
|
||
err = createSecret(clientset, *namespace, *secretName, certificate, key) | ||
if err != nil { | ||
log.Fatalf("Failed to create Secret: %v", err) | ||
} | ||
} |
5 changes: 1 addition & 4 deletions
5
...r/kind-k8s-sriov-1.17.0/csrcreator/go.mod → .../kind-k8s-sriov-1.17.0/certcreator/go.mod
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.