From 38dcb2e94f2bfb03142c79ee1bba008ab35534bb Mon Sep 17 00:00:00 2001
From: shivkumar dudhani <shivkumar@nirmata.com>
Date: Mon, 6 Jan 2020 16:12:53 -0800
Subject: [PATCH 1/4] flag to use FQDN as CommonName in CSR

---
 cmd/kyverno/main.go         |  8 +++++---
 pkg/dclient/certificates.go | 16 ++++++++--------
 pkg/tls/tls.go              | 38 ++++++++++++++++++++-----------------
 3 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go
index aee3c434a8..8858429c4a 100644
--- a/cmd/kyverno/main.go
+++ b/cmd/kyverno/main.go
@@ -27,12 +27,12 @@ import (
 var (
 	kubeconfig     string
 	serverIP       string
-	cpu            bool
-	memory         bool
 	webhookTimeout int
 	//TODO: this has been added to backward support command line arguments
 	// will be removed in future and the configuration will be set only via configmaps
 	filterK8Resources string
+	// User FQDN as CSR CN
+	FQDNCN bool
 )
 
 func main() {
@@ -168,7 +168,7 @@ func main() {
 		policyMetaStore)
 
 	// CONFIGURE CERTIFICATES
-	tlsPair, err := client.InitTLSPemPair(clientConfig)
+	tlsPair, err := client.InitTLSPemPair(clientConfig, FQDNCN)
 	if err != nil {
 		glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
 	}
@@ -246,6 +246,8 @@ func init() {
 	flag.IntVar(&webhookTimeout, "webhooktimeout", 3, "timeout for webhook configurations")
 	flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
 	flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
+	// Generate CSR with CN as FQDN due to https://github.com/nirmata/kyverno/issues/542
+	flag.BoolVar(&FQDNCN, "FQDNAsCN", false, "use FQDN as Common Name in CSR")
 	config.LogDefaultFlags()
 	flag.Parse()
 }
diff --git a/pkg/dclient/certificates.go b/pkg/dclient/certificates.go
index 090302c940..a12dec71cb 100644
--- a/pkg/dclient/certificates.go
+++ b/pkg/dclient/certificates.go
@@ -18,15 +18,15 @@ import (
 // InitTLSPemPair Loads or creates PEM private key and TLS certificate for webhook server.
 // Created pair is stored in cluster's secret.
 // Returns struct with key/certificate pair.
-func (c *Client) InitTLSPemPair(configuration *rest.Config) (*tls.TlsPemPair, error) {
+func (c *Client) InitTLSPemPair(configuration *rest.Config, FQDNCN bool) (*tls.TlsPemPair, error) {
 	certProps, err := c.GetTLSCertProps(configuration)
 	if err != nil {
 		return nil, err
 	}
 	tlsPair := c.ReadTlsPair(certProps)
-	if tls.IsTlsPairShouldBeUpdated(tlsPair) {
+	if tls.IsTLSPairShouldBeUpdated(tlsPair) {
 		glog.Info("Generating new key/certificate pair for TLS")
-		tlsPair, err = c.GenerateTlsPemPair(certProps)
+		tlsPair, err = c.generateTLSPemPair(certProps, FQDNCN)
 		if err != nil {
 			return nil, err
 		}
@@ -40,15 +40,15 @@ func (c *Client) InitTLSPemPair(configuration *rest.Config) (*tls.TlsPemPair, er
 	return tlsPair, nil
 }
 
-//GenerateTlsPemPair Issues TLS certificate for webhook server using given PEM private key
+//generateTlsPemPair Issues TLS certificate for webhook server using given PEM private key
 // Returns signed and approved TLS certificate in PEM format
-func (c *Client) GenerateTlsPemPair(props tls.TlsCertificateProps) (*tls.TlsPemPair, error) {
-	privateKey, err := tls.TlsGeneratePrivateKey()
+func (c *Client) generateTLSPemPair(props tls.TlsCertificateProps, FQDNCN bool) (*tls.TlsPemPair, error) {
+	privateKey, err := tls.TLSGeneratePrivateKey()
 	if err != nil {
 		return nil, err
 	}
 
-	certRequest, err := tls.TlsCertificateGenerateRequest(privateKey, props)
+	certRequest, err := tls.CertificateGenerateRequest(privateKey, props, FQDNCN)
 	if err != nil {
 		return nil, fmt.Errorf("Unable to create certificate request: %v", err)
 	}
@@ -65,7 +65,7 @@ func (c *Client) GenerateTlsPemPair(props tls.TlsCertificateProps) (*tls.TlsPemP
 
 	return &tls.TlsPemPair{
 		Certificate: tlsCert,
-		PrivateKey:  tls.TlsPrivateKeyToPem(privateKey),
+		PrivateKey:  tls.TLSPrivateKeyToPem(privateKey),
 	}, nil
 }
 
diff --git a/pkg/tls/tls.go b/pkg/tls/tls.go
index 93055f7c74..bb640ad560 100644
--- a/pkg/tls/tls.go
+++ b/pkg/tls/tls.go
@@ -27,13 +27,13 @@ type TlsPemPair struct {
 	PrivateKey  []byte
 }
 
-//TlsGeneratePrivateKey Generates RSA private key
-func TlsGeneratePrivateKey() (*rsa.PrivateKey, error) {
+//TLSGeneratePrivateKey Generates RSA private key
+func TLSGeneratePrivateKey() (*rsa.PrivateKey, error) {
 	return rsa.GenerateKey(rand.Reader, 2048)
 }
 
-//TlsPrivateKeyToPem Creates PEM block from private key object
-func TlsPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
+//TLSPrivateKeyToPem Creates PEM block from private key object
+func TLSPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
 	privateKey := &pem.Block{
 		Type:  "PRIVATE KEY",
 		Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
@@ -43,7 +43,7 @@ func TlsPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
 }
 
 //TlsCertificateRequestToPem Creates PEM block from raw certificate request
-func TlsCertificateRequestToPem(csrRaw []byte) []byte {
+func certificateRequestToPem(csrRaw []byte) []byte {
 	csrBlock := &pem.Block{
 		Type:  "CERTIFICATE REQUEST",
 		Bytes: csrRaw,
@@ -52,26 +52,30 @@ func TlsCertificateRequestToPem(csrRaw []byte) []byte {
 	return pem.EncodeToMemory(csrBlock)
 }
 
-//TlsCertificateGenerateRequest Generates raw certificate signing request
-func TlsCertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificateProps) (*certificates.CertificateSigningRequest, error) {
+//CertificateGenerateRequest Generates raw certificate signing request
+func CertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificateProps, FQDNCN bool) (*certificates.CertificateSigningRequest, error) {
 	dnsNames := make([]string, 3)
 	dnsNames[0] = props.Service
 	dnsNames[1] = props.Service + "." + props.Namespace
 	// The full service name is the CommonName for the certificate
 	commonName := GenerateInClusterServiceName(props)
 	dnsNames[2] = commonName
-
+	csCommonName := props.Service
+	if FQDNCN {
+		// use FQDN as CommonName as a workaournd for https://github.com/nirmata/kyverno/issues/542
+		csCommonName = commonName
+	}
 	var ips []net.IP
-	apiServerIp := net.ParseIP(props.ApiServerHost)
-	if apiServerIp != nil {
-		ips = append(ips, apiServerIp)
+	apiServerIP := net.ParseIP(props.ApiServerHost)
+	if apiServerIP != nil {
+		ips = append(ips, apiServerIP)
 	} else {
 		dnsNames = append(dnsNames, props.ApiServerHost)
 	}
 
 	csrTemplate := x509.CertificateRequest{
 		Subject: pkix.Name{
-			CommonName: props.Service, //commonName,
+			CommonName: csCommonName,
 		},
 		SignatureAlgorithm: x509.SHA256WithRSA,
 		DNSNames:           dnsNames,
@@ -92,7 +96,7 @@ func TlsCertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertific
 			Name: props.Service + "." + props.Namespace + ".cert-request",
 		},
 		Spec: certificates.CertificateSigningRequestSpec{
-			Request: TlsCertificateRequestToPem(csrBytes),
+			Request: certificateRequestToPem(csrBytes),
 			Groups:  []string{"system:masters", "system:authenticated"},
 			Usages: []certificates.KeyUsage{
 				certificates.UsageDigitalSignature,
@@ -110,7 +114,7 @@ func GenerateInClusterServiceName(props TlsCertificateProps) string {
 }
 
 //TlsCertificateGetExpirationDate Gets NotAfter property from raw certificate
-func TlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
+func tlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
 	block, _ := pem.Decode(certData)
 	if block == nil {
 		return nil, errors.New("Failed to decode PEM")
@@ -127,13 +131,13 @@ func TlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
 // an expired certificate in a controller that has been running for a long time
 const timeReserveBeforeCertificateExpiration time.Duration = time.Hour * 24 * 30 * 6 // About half a year
 
-//IsTlsPairShouldBeUpdated checks if TLS pair has expited and needs to be updated
-func IsTlsPairShouldBeUpdated(tlsPair *TlsPemPair) bool {
+//IsTLSPairShouldBeUpdated checks if TLS pair has expited and needs to be updated
+func IsTLSPairShouldBeUpdated(tlsPair *TlsPemPair) bool {
 	if tlsPair == nil {
 		return true
 	}
 
-	expirationDate, err := TlsCertificateGetExpirationDate(tlsPair.Certificate)
+	expirationDate, err := tlsCertificateGetExpirationDate(tlsPair.Certificate)
 	if err != nil {
 		return true
 	}

From 1e5f87166566529d874f29d1cfa8d06648626e08 Mon Sep 17 00:00:00 2001
From: shivkumar dudhani <shivkumar@nirmata.com>
Date: Wed, 8 Jan 2020 16:40:19 -0800
Subject: [PATCH 2/4] lowercase the cmdline arg

---
 cmd/kyverno/main.go         | 6 +++---
 pkg/dclient/certificates.go | 8 ++++----
 pkg/tls/tls.go              | 4 ++--
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go
index 8858429c4a..475dcaa790 100644
--- a/cmd/kyverno/main.go
+++ b/cmd/kyverno/main.go
@@ -32,7 +32,7 @@ var (
 	// will be removed in future and the configuration will be set only via configmaps
 	filterK8Resources string
 	// User FQDN as CSR CN
-	FQDNCN bool
+	fqdncn bool
 )
 
 func main() {
@@ -168,7 +168,7 @@ func main() {
 		policyMetaStore)
 
 	// CONFIGURE CERTIFICATES
-	tlsPair, err := client.InitTLSPemPair(clientConfig, FQDNCN)
+	tlsPair, err := client.InitTLSPemPair(clientConfig, fqdncn)
 	if err != nil {
 		glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
 	}
@@ -247,7 +247,7 @@ func init() {
 	flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
 	flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
 	// Generate CSR with CN as FQDN due to https://github.com/nirmata/kyverno/issues/542
-	flag.BoolVar(&FQDNCN, "FQDNAsCN", false, "use FQDN as Common Name in CSR")
+	flag.BoolVar(&fqdncn, "fqdn-as-cn", false, "use FQDN as Common Name in CSR")
 	config.LogDefaultFlags()
 	flag.Parse()
 }
diff --git a/pkg/dclient/certificates.go b/pkg/dclient/certificates.go
index a12dec71cb..1f499f829c 100644
--- a/pkg/dclient/certificates.go
+++ b/pkg/dclient/certificates.go
@@ -18,7 +18,7 @@ import (
 // InitTLSPemPair Loads or creates PEM private key and TLS certificate for webhook server.
 // Created pair is stored in cluster's secret.
 // Returns struct with key/certificate pair.
-func (c *Client) InitTLSPemPair(configuration *rest.Config, FQDNCN bool) (*tls.TlsPemPair, error) {
+func (c *Client) InitTLSPemPair(configuration *rest.Config, fqdncn bool) (*tls.TlsPemPair, error) {
 	certProps, err := c.GetTLSCertProps(configuration)
 	if err != nil {
 		return nil, err
@@ -26,7 +26,7 @@ func (c *Client) InitTLSPemPair(configuration *rest.Config, FQDNCN bool) (*tls.T
 	tlsPair := c.ReadTlsPair(certProps)
 	if tls.IsTLSPairShouldBeUpdated(tlsPair) {
 		glog.Info("Generating new key/certificate pair for TLS")
-		tlsPair, err = c.generateTLSPemPair(certProps, FQDNCN)
+		tlsPair, err = c.generateTLSPemPair(certProps, fqdncn)
 		if err != nil {
 			return nil, err
 		}
@@ -42,13 +42,13 @@ func (c *Client) InitTLSPemPair(configuration *rest.Config, FQDNCN bool) (*tls.T
 
 //generateTlsPemPair Issues TLS certificate for webhook server using given PEM private key
 // Returns signed and approved TLS certificate in PEM format
-func (c *Client) generateTLSPemPair(props tls.TlsCertificateProps, FQDNCN bool) (*tls.TlsPemPair, error) {
+func (c *Client) generateTLSPemPair(props tls.TlsCertificateProps, fqdncn bool) (*tls.TlsPemPair, error) {
 	privateKey, err := tls.TLSGeneratePrivateKey()
 	if err != nil {
 		return nil, err
 	}
 
-	certRequest, err := tls.CertificateGenerateRequest(privateKey, props, FQDNCN)
+	certRequest, err := tls.CertificateGenerateRequest(privateKey, props, fqdncn)
 	if err != nil {
 		return nil, fmt.Errorf("Unable to create certificate request: %v", err)
 	}
diff --git a/pkg/tls/tls.go b/pkg/tls/tls.go
index bb640ad560..c91c9b922c 100644
--- a/pkg/tls/tls.go
+++ b/pkg/tls/tls.go
@@ -53,7 +53,7 @@ func certificateRequestToPem(csrRaw []byte) []byte {
 }
 
 //CertificateGenerateRequest Generates raw certificate signing request
-func CertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificateProps, FQDNCN bool) (*certificates.CertificateSigningRequest, error) {
+func CertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificateProps, fqdncn bool) (*certificates.CertificateSigningRequest, error) {
 	dnsNames := make([]string, 3)
 	dnsNames[0] = props.Service
 	dnsNames[1] = props.Service + "." + props.Namespace
@@ -61,7 +61,7 @@ func CertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificate
 	commonName := GenerateInClusterServiceName(props)
 	dnsNames[2] = commonName
 	csCommonName := props.Service
-	if FQDNCN {
+	if fqdncn {
 		// use FQDN as CommonName as a workaournd for https://github.com/nirmata/kyverno/issues/542
 		csCommonName = commonName
 	}

From 7b3867650594b44ab05325461449006504e1f859 Mon Sep 17 00:00:00 2001
From: shivkumar dudhani <shivkumar@nirmata.com>
Date: Thu, 9 Jan 2020 09:52:09 -0800
Subject: [PATCH 3/4] remove nonsupported flags from comments

---
 definitions/install.yaml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/definitions/install.yaml b/definitions/install.yaml
index 7c7d1fe95e..8e030a44cf 100644
--- a/definitions/install.yaml
+++ b/definitions/install.yaml
@@ -468,8 +468,6 @@ spec:
           - "--filterK8Resources=[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][*,kyverno,*]"
           # customize webhook timout
           # - "--webhooktimeout=4"
-          # open one of the profiling flag here
-          # - "--cpu=true"
           ports:
           - containerPort: 443
           env:

From 291c111b8c1a1021e64f6753f3ed796c4e40a1ad Mon Sep 17 00:00:00 2001
From: shivkumar dudhani <shivkumar@nirmata.com>
Date: Thu, 9 Jan 2020 12:20:08 -0800
Subject: [PATCH 4/4] update documentation for fqdncn

---
 documentation/installation.md | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/documentation/installation.md b/documentation/installation.md
index 9c470afca4..5c609f283f 100644
--- a/documentation/installation.md
+++ b/documentation/installation.md
@@ -10,6 +10,8 @@ There are 2 ways to configure the secure communications link between Kyverno and
 
 Kyverno can request a CA signed certificate-key pair from `kube-controller-manager`. This method requires that the kube-controller-manager is configured to act as a certificate signer. To verify that this option is enabled for your cluster, check the command-line args for the kube-controller-manager. If `--cluster-signing-cert-file` and `--cluster-signing-key-file` are passed to the controller manager with paths to your CA's key-pair, then you can proceed to install Kyverno using this method.
 
+**Deploying on EKS requires enabling a command-line argument `--fqdncn` in the 'kyverno' container in the deployment, due to a current limitation with the certificates returned by EKS for CSR(bug: https://github.com/awslabs/amazon-eks-ami/issues/341)**
+
 To install Kyverno in a cluster that supports certificate signing, run the following command on a host with kubectl `cluster-admin` access:
 
 ````sh
@@ -130,11 +132,6 @@ To run controller in this mode you should prepare TLS key/certificate pair for d
 
 2. Start the controller using the following command: `sudo kyverno --kubeconfig=~/.kube/config --serverIP=<server_IP>`
 
-# Try Kyverno without a Kubernetes cluster
-
-The [Kyverno CLI](documentation/testing-policies.md#test-using-the-kyverno-cli) allows you to write and test policies without installing Kyverno in a Kubernetes cluster. Some features are not supported without a Kubernetes cluster.
-
-
 # Filter kuberenetes resources that admission webhook should not process
 The admission webhook checks if a policy is applicable on all admission requests. The kubernetes kinds that are not be processed can be filtered by adding the configmap named `init-config` in namespace `kyverno` and specifying the resources to be filtered under `data.resourceFilters`
 
@@ -152,7 +149,8 @@ data:
 ```
 
 By default we have specified Nodes, Events, APIService & SubjectAccessReview as the kinds to be skipped in the default configmap
-[install.yaml](https://github.com/nirmata/kyverno/raw/master/definitions/init_configMap.yaml).
+[install.yaml](https://github.com/nirmata/kyverno/raw/master/definitions/install.yaml).
+
 
 ---
 <small>*Read Next >> [Writing Policies](/documentation/writing-policies.md)*</small>