From 27eb5220a1e33ac8180c64414827c6923b448580 Mon Sep 17 00:00:00 2001 From: Tomasz Wrobel Date: Fri, 23 Oct 2020 08:34:41 +0200 Subject: [OOM-K8S-CERT-EXTERNAL-PROVIDER] Add logging of not supported/overridden CSR info Issue-ID: OOM-2559 Change-Id: I0199712e70d65650dd7ce0c0b95537373f94f7a4 Signed-off-by: Tomasz Wrobel --- .../certificate_request_controller.go | 8 +- .../logger/certificate_request_logger.go | 130 +++++++++++++++++++++ .../logger/certificate_request_logger_test.go | 121 +++++++++++++++++++ .../src/cmpv2controller/logger/test_resource.go | 63 ++++++++++ 4 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go create mode 100644 certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go create mode 100644 certServiceK8sExternalProvider/src/cmpv2controller/logger/test_resource.go (limited to 'certServiceK8sExternalProvider/src/cmpv2controller') diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go b/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go index d526bbc8..81af0d36 100644 --- a/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go +++ b/certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller.go @@ -41,6 +41,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api" + "onap.org/oom-certservice/k8s-external-provider/src/cmpv2controller/logger" provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner" ) @@ -122,14 +123,17 @@ func (controller *CertificateRequestController) Reconcile(k8sRequest ctrl.Reques } privateKeyBytes := privateKeySecret.Data[privateKeySecretKey] - // 8. Sign CertificateRequest + // 8. Log Certificate Request properties not supported or overridden by CertService API + logger.LogCertRequestProperties(ctrl.Log.WithName("CSR details"), certificateRequest) + + // 9. Sign CertificateRequest signedPEM, trustedCAs, err := provisioner.Sign(ctx, certificateRequest, privateKeyBytes) if err != nil { controller.handleErrorFailedToSignCertificate(ctx, log, err, certificateRequest) return ctrl.Result{}, err } - // 9. Store signed certificates in CertificateRequest + // 10. Store signed certificates in CertificateRequest certificateRequest.Status.Certificate = signedPEM certificateRequest.Status.CA = trustedCAs if err := controller.updateCertificateRequestWithSignedCerficates(ctx, certificateRequest); err != nil { diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go new file mode 100644 index 00000000..da439fb8 --- /dev/null +++ b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger.go @@ -0,0 +1,130 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package logger + +import ( + "crypto/x509" + "encoding/pem" + "net" + "net/url" + "strconv" + + "github.com/go-logr/logr" + cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" +) + +const ( + CertServiceName = "Cert Service API" + CMPv2ServerName = "CMPv2 Server" +) + +func LogCertRequestProperties(log logr.Logger, request *cmapi.CertificateRequest) { + logPropertiesOverriddenByCMPv2Server(log, request) + logPropertiesNotSupportedByCertService(log, request) +} + +func logPropertiesOverriddenByCMPv2Server(log logr.Logger, request *cmapi.CertificateRequest) { + if request.Spec.Duration != nil && len(request.Spec.Duration.String()) > 0 { + log.Info(getOverriddenMessage("duration", request.Spec.Duration.Duration.String())) + } + if request.Spec.Usages != nil && len(request.Spec.Usages) > 0 { + log.Info(getOverriddenMessage("usages", extractUsages(request.Spec.Usages))) + } +} + +func extractUsages(usages []cmapi.KeyUsage) string { + values := "" + for _, usage := range usages { + values = values + string(usage) + ", " + } + return values +} + +func getOverriddenMessage(property string, values string) string { + return "Property '" + property + "' with value: " + values + ", will be overridden by " + CMPv2ServerName +} + +func logPropertiesNotSupportedByCertService(log logr.Logger, request *cmapi.CertificateRequest) { + + block, _ := pem.Decode(request.Spec.Request) + cert, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + log.Error(err, "Cannot parse Certificate Signing Request") + } + //IP addresses in SANs + if len(cert.IPAddresses) > 0 { + log.Info(getNotSupportedMessage("ipAddresses", extractIPAddresses(cert.IPAddresses))) + } + //URIs in SANs + if len(cert.URIs) > 0 { + log.Info(getNotSupportedMessage("uris", extractURIs(cert.URIs))) + } + + //Email addresses in SANs + if len(cert.EmailAddresses) > 0 { + log.Info(getNotSupportedMessage("emailAddresses", extractStringArray(cert.EmailAddresses))) + } + + if request.Spec.IsCA == true { + log.Info(getNotSupportedMessage("isCA", strconv.FormatBool(request.Spec.IsCA))) + } + + if len(cert.Subject.StreetAddress) > 0 { + log.Info(getNotSupportedMessage("subject.streetAddress", extractStringArray(cert.Subject.StreetAddress))) + } + + if len(cert.Subject.PostalCode) > 0 { + log.Info(getNotSupportedMessage("subject.postalCodes", extractStringArray(cert.Subject.PostalCode))) + } + + if len(cert.Subject.SerialNumber) > 0 { + log.Info(getNotSupportedMessage("subject.serialNumber", cert.Subject.SerialNumber)) + } + +} + +func extractStringArray(strArray []string) string { + values := "" + for _, emailSANs := range strArray { + values = values + emailSANs + ", " + } + return values +} + +func extractURIs(URIs []*url.URL) string { + values := "" + for _, uri := range URIs { + values = values + uri.String() + ", " + } + return values +} + +func extractIPAddresses(addresses []net.IP) string { + values := "" + for _, ipAddress := range addresses { + values = values + ipAddress.String() + ", " + } + return values +} + +func getNotSupportedMessage(property string, values string) string { + return "WARNING: Property '" + property + "' with value: " + values + " is not supported by " + CertServiceName +} diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go new file mode 100644 index 00000000..7d1abc2c --- /dev/null +++ b/certServiceK8sExternalProvider/src/cmpv2controller/logger/certificate_request_logger_test.go @@ -0,0 +1,121 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package logger + +import ( + "bytes" + "flag" + "os" + "strings" + "testing" + "time" + + cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" + "k8s.io/klog/v2/klogr" +) + +var checkedLogMessages = [7]string{"Property 'duration'", "Property 'usages'", "Property 'ipAddresses'", + "Property 'isCA'", "Property 'subject.streetAddress'", "Property 'subject.postalCodes'", + "Property 'subject.serialNumber'"} + +func TestMain(m *testing.M) { + klog.InitFlags(nil) + flag.CommandLine.Set("v", "10") + flag.CommandLine.Set("skip_headers", "true") + flag.CommandLine.Set("logtostderr", "false") + flag.CommandLine.Set("alsologtostderr", "false") + flag.Parse() + os.Exit(m.Run()) +} + +func TestLogShouldNotProvideInformationAboutSkippedPropertiesIfNotExistInCSR(t *testing.T) { + //given + logger := klogr.New() + request := getCertificateRequestWithoutSkippedProperties() + tmpWriteBuffer := getLogBuffer() + + //when + LogCertRequestProperties(logger, request) + closeLogBuffer() + logsArray := convertBufferToStringArray(tmpWriteBuffer) + //then + for _, logMsg := range checkedLogMessages { + assert.False(t, logsContainExpectedMessage(logsArray, logMsg), "Logs contain: "+logMsg+", but should not") + } +} + +func TestLogShouldProvideInformationAboutSkippedPropertiesIfExistInCSR(t *testing.T) { + //given + logger := klogr.New() + request := getCertificateRequestWithSkippedProperties() + tmpWriteBuffer := getLogBuffer() + + //when + LogCertRequestProperties(logger, request) + closeLogBuffer() + logsArray := convertBufferToStringArray(tmpWriteBuffer) + + //then + for _, logMsg := range checkedLogMessages { + assert.True(t, logsContainExpectedMessage(logsArray, logMsg), "Logs not contain: "+logMsg) + } +} + +func getCertificateRequestWithoutSkippedProperties() *cmapi.CertificateRequest { + request := new(cmapi.CertificateRequest) + request.Spec.Request = []byte(csrWithoutSkippedProperties) + return request +} + +func getCertificateRequestWithSkippedProperties() *cmapi.CertificateRequest { + request := new(cmapi.CertificateRequest) + request.Spec.Request = []byte(csrWithSkippedProperties) + request.Spec.Duration = &metav1.Duration{Duration: time.Hour} + request.Spec.IsCA = true + request.Spec.Usages = cmapi.DefaultKeyUsages() + return request +} + +func getLogBuffer() *bytes.Buffer { + tmpWriteBuffer := bytes.NewBuffer(nil) + klog.SetOutput(tmpWriteBuffer) + return tmpWriteBuffer +} + +func closeLogBuffer() { + klog.Flush() +} + +func convertBufferToStringArray(buffer *bytes.Buffer) []string { + return strings.Split(buffer.String(), "\n") +} + +func logsContainExpectedMessage(array []string, expectedMsg string) bool { + for _, logMsg := range array { + if strings.Contains(logMsg, expectedMsg) { + return true + } + } + return false +} diff --git a/certServiceK8sExternalProvider/src/cmpv2controller/logger/test_resource.go b/certServiceK8sExternalProvider/src/cmpv2controller/logger/test_resource.go new file mode 100644 index 00000000..c0f6f950 --- /dev/null +++ b/certServiceK8sExternalProvider/src/cmpv2controller/logger/test_resource.go @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * oom-certservice-k8s-external-provider + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package logger + +const csrWithoutSkippedProperties = (`-----BEGIN CERTIFICATE REQUEST----- +MIIDETCCAfkCAQAwgYIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh +MRYwFAYDVQQHEw1TYW4tRnJhbmNpc2NvMRkwFwYDVQQKExBMaW51eC1Gb3VuZGF0 +aW9uMQ0wCwYDVQQLEwRPTkFQMRwwGgYDVQQDExNjZXJ0aXNzdWVyLm9uYXAub3Jn +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxhQiSgyYGpEfX/HuCFwT +GHkLe1CheKz2CQzSP9an5BSdET1OgABmuJjtnXZzKpPAZCGJX2QTyDE9zvdTN0Ci +/8WRL/m2tWUPbt8qRVW36PSKazpB+ELZjQi3rmYtmWUlRuJNfLcksK59pcD5W46t +d9eettkex0FAcxpQE/ukhpW9r6QrmlQAQHuF1rBw6uJMGzFSPWh9XFLFbxZJyJCu +AIycvT95bgtot3EMPwGkxAYzxtAu6D5/n65nIZ0f9BuuNFtmnoHmn/9fPUnZHA0h +qP9kXAAU10S3gig+Na6DeZFBE1y9jCt4vmSq2ssBO24kOAHrg5GrqEsnfoSnu8Nb +sQIDAQABoEkwRwYJKoZIhvcNAQkOMTowODApBgNVHREEIjAggglsb2NhbGhvc3SC +E2NlcnRpc3N1ZXIub25hcC5vcmcwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUA +A4IBAQAWkOeJHnmtlSvlb7HbBeSGY4E9M338sKtwV4ZSvH+n5rgwamkvjhUwhycs +UR0XgeAyD86kK6kkvVewdIanHYp1k7CuDZkU6piy8t4RhosyqUWQNWtemGYdNZCL +cgZ1Jbj4NdIZo2EKBIEbTrm9VFt1zidYRFNGNJp8RQQds6r4qATq1NKr6ptrLuIc +dzfOm1ZPtSn8u4H4+z1re6q18JeM0VPXBiXBtEXwQRXIEnsjCzYxdjy+QwbEmlpB +o2hMIamWNIbskYnNkaky8eQzjJ8uIesESeanWJlrMUbzicOwQeYMPmj+Mkn1nqlK +YFwml5XnVXXpGLHGWCswpN3CDyXi +-----END CERTIFICATE REQUEST-----`) + +const csrWithSkippedProperties = (`-----BEGIN CERTIFICATE REQUEST----- +MIIDgjCCAmoCAQAwgaQxCzAJBgNVBAYTAlBMMRMwEQYDVQQIEwpEb2xueVNsYXNr +MRAwDgYDVQQHEwdXcm9jbGF3MREwDwYDVQQJEwhMb3RuaWN6YTEPMA0GA1UEERMG +MTItMzQ1MQ0wCwYDVQQKEwRPTkFQMQ0wCwYDVQQLEwRvbmFwMRwwGgYDVQQDExNj +ZXJ0aXNzdWVyLm9uYXAub3JnMQ4wDAYDVQQFEwUxMjM0NTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAPdrWRYpdGY6A9YEQ8mnQdOW7wzdaNHJ83ZrMPZd +V7jBOMvQbTw6Oe/Q4vD+Dla7FmGqlAajNIgKRiUUQLKVmASELhCYhtW7Mn91qe6l +xuyPyOEi9o8mArJosFAfPPF0nm9FQPi2qHgyi6C52QR7cKsgNPflpKVsEx9Y+Zns +YBqkaX16BukvcHUANgsvZ3rLUVeiOsCi2ysVcsm+4XMvF6ejoqKJ9k7Ti0VrQtqh +e1nKlaa4uP3dreeUXBMLfKUS7QrNavpiX6wVaohVp6p/AYQ2HZurMv86Q2E5D5SC +ReEpVuWx+r4MI8dAHbYe09ntkRGIe8mVyxHHEWLNfZiwKGsCAwEAAaCBlzCBlAYJ +KoZIhvcNAQkOMYGGMIGDMFUGA1UdEQROMEyCCWxvY2FsaG9zdIITY2VydGlzc3Vl +ci5vbmFwLm9yZ4ENb25hcEBvbmFwLm9yZ4cEfwAAAYYVb25hcDovL2NsdXN0ZXIu +bG9jYWwvMAsGA1UdDwQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH +AwIwDQYJKoZIhvcNAQELBQADggEBAHDMw3+fVOrbVnMI2g/IP40vt1eenkoriTHX +dnjRRFio75nCNRJdLOJ9FU3wIgdDZwGaiXdn5NDQxCe0BWcbElDJSYR/xOi7V0AM +2L3CrRAOhr2MjwX7CaOuYWcVtrbtIMf26NLKRXYPlGgc6YeofalDnezMJ/IuRQhj +bcm17a8owa5dH9u/rmTmlrIT7PV4JHkZIogctIcSqod6xdr1mbi8G9DMFAqV+o7W +9kV7XDKhTqYoBIsXwfehNMu3lo72VuklIyVNiEVz4mVzpeZy2DgjRjCLt106yDHZ +f3nco6O4y2EyexBVKq6QRFfZDUab6YcoEVvPAio01RmFrHgnxHs= +-----END CERTIFICATE REQUEST-----`) -- cgit 1.2.3-korg