diff --git a/CHANGELOG.md b/CHANGELOG.md index 7286bf667f..9624e011a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - [#6034](https://github.com/apache/trafficcontrol/issues/6034) Added new query parameter `cdn` to the `GET /api/x/deliveryserviceserver` Traffic Ops API to filter by CDN name - Added a new Traffic Monitor configuration option -- `short_hostname_override` -- to traffic_monitor.cfg to allow overriding the system hostname that Traffic Monitor uses. - A new Traffic Portal server command-line option `-c` to specify a configuration file, and the ability to set `log: null` to log to stdout (consult documentation for details). +- SANs information to the SSL key endpoint and Traffic Portal page. ### Fixed - Fixed Traffic Router crs/stats to prevent overflow and to correctly record the time used in averages. diff --git a/docs/source/api/v4/deliveryservices_xmlid_xmlid_sslkeys.rst b/docs/source/api/v4/deliveryservices_xmlid_xmlid_sslkeys.rst index efc2cb5eb6..3130a23215 100644 --- a/docs/source/api/v4/deliveryservices_xmlid_xmlid_sslkeys.rst +++ b/docs/source/api/v4/deliveryservices_xmlid_xmlid_sslkeys.rst @@ -71,6 +71,9 @@ Response Structure :state: An optional field which, if present, contains the state entered by the user when generating certificate\ [1]_ :version: An integer that defines the "version" of the key - which may be thought of as the sequential generation; that is, the higher the number the more recent the key :expiration: The expiration date of the certificate for the :term:`Delivery Service` in :rfc:`3339` format +:sans: The :abbr:`SANs (Subject Alternate Names)` from the SSL certificate. + + .. versionadded:: 4.1 .. code-block:: http :caption: Response Example @@ -93,7 +96,8 @@ Response Structure "country": "US", "state": "Colorado", "version": "1", - "expiration": "2020-08-18T13:53:06Z" + "expiration": "2020-08-18T13:53:06Z", + "sans": ["*.foober.com", "*.foober2.com"] }} ``DELETE`` diff --git a/lib/go-tc/deliveryservice_ssl_keys.go b/lib/go-tc/deliveryservice_ssl_keys.go index ec6dc4c904..fd6772247a 100644 --- a/lib/go-tc/deliveryservice_ssl_keys.go +++ b/lib/go-tc/deliveryservice_ssl_keys.go @@ -65,6 +65,20 @@ type DeliveryServiceSSLKeys struct { Certificate DeliveryServiceSSLKeysCertificate `json:"certificate,omitempty"` } +// DeliveryServiceSSLKeysV4 is the representation of a DeliveryServiceSSLKeys in the latest minor version of +// version 4 of the Traffic Ops API. +type DeliveryServiceSSLKeysV4 = DeliveryServiceSSLKeysV41 + +// DeliveryServiceSSLKeysV41 structures contain information about an SSL key +// certificate pair used by a Delivery Service. +// +// "V41" is used because this structure was first introduced in version 4.1 of +// the Traffic Ops API. +type DeliveryServiceSSLKeysV41 struct { + DeliveryServiceSSLKeysV15 + Sans []string `json:"sans,omitempty"` +} + // DeliveryServiceSSLKeysV15 structures contain information about an SSL key // certificate pair used by a Delivery Service. // @@ -73,7 +87,7 @@ type DeliveryServiceSSLKeys struct { // // This is, ostensibly, an updated version of DeliveryServiceSSLKeys, but // beware that this may not be completely accurate as the predecessor structure -// appears to be used in many more contexts than this this structure. +// appears to be used in many more contexts than this structure. type DeliveryServiceSSLKeysV15 struct { DeliveryServiceSSLKeys Expiration time.Time `json:"expiration,omitempty"` diff --git a/lib/go-util/str.go b/lib/go-util/str.go index 842def71df..755fc8cb65 100644 --- a/lib/go-util/str.go +++ b/lib/go-util/str.go @@ -49,6 +49,17 @@ func StrInArray(strs []string, s string) bool { return false } +// RemoveStrFromArray removes a specific string from a string slice. +func RemoveStrFromArray(strs []string, s string) []string { + newStrArray := []string{} + for _, str := range strs { + if str != s { + newStrArray = append(newStrArray, str) + } + } + return newStrArray +} + func ContainsStr(a []string, x string) bool { for _, n := range a { if x == n { diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/autorenewcerts.go b/traffic_ops/traffic_ops_golang/deliveryservice/autorenewcerts.go index 05327d2b72..84be21f928 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/autorenewcerts.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/autorenewcerts.go @@ -208,7 +208,7 @@ func RunAutorenewal(existingCerts []ExistingCerts, cfg *config.Config, ctx conte continue } - expiration, err := parseExpirationFromCert([]byte(keyObj.Certificate.Crt)) + expiration, _, err := parseExpirationAndSansFromCert([]byte(keyObj.Certificate.Crt), keyObj.Hostname) if err != nil { log.Errorf("cert autorenewal: %s: %s", ds.XmlId, err.Error()) dsExpInfo.XmlId = ds.XmlId diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go index 79fcd69dd9..b4d1502735 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/keys.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/keys.go @@ -21,6 +21,7 @@ package deliveryservice import ( "bytes" + "context" "crypto/ecdsa" "crypto/rsa" "crypto/x509" @@ -135,8 +136,8 @@ func AddSSLKeys(w http.ResponseWriter, r *http.Request) { api.WriteResp(w, r, "Successfully added ssl keys for "+*req.DeliveryService) } -// GetSSLKeysByXMLIDV15 fetches the deliveryservice ssl keys by the specified xmlID. V15 includes expiration date. -func GetSSLKeysByXMLIDV15(w http.ResponseWriter, r *http.Request) { +// GetSSLKeysByXMLID fetches the deliveryservice ssl keys by the specified xmlID. V15 includes expiration date. +func GetSSLKeysByXMLID(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"xmlid"}, nil) if userErr != nil || sysErr != nil { api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) @@ -149,67 +150,83 @@ func GetSSLKeysByXMLIDV15(w http.ResponseWriter, r *http.Request) { } xmlID := inf.Params["xmlid"] alerts := tc.Alerts{} - version := inf.Params["version"] - decode := inf.Params["decode"] if userErr, sysErr, errCode := tenant.Check(inf.User, xmlID, inf.Tx.Tx); userErr != nil || sysErr != nil { userErr = api.LogErr(r, errCode, userErr, sysErr) alerts.AddNewAlert(tc.ErrorLevel, userErr.Error()) api.WriteAlerts(w, r, errCode, alerts) return } - keyObj, ok, err := inf.Vault.GetDeliveryServiceSSLKeys(xmlID, version, inf.Tx.Tx, r.Context()) + + keyObjV4, err := getSslKeys(inf, r.Context()) if err != nil { - userErr := api.LogErr(r, http.StatusInternalServerError, nil, errors.New("getting ssl keys: "+err.Error())) + userErr := api.LogErr(r, http.StatusInternalServerError, nil, err) alerts.AddNewAlert(tc.ErrorLevel, userErr.Error()) api.WriteAlerts(w, r, http.StatusInternalServerError, alerts) return } - if !ok { - keyObj = tc.DeliveryServiceSSLKeysV15{} + + var keyObj interface{} + if inf.Version.Major < 4 || (inf.Version.Major == 4 && inf.Version.Minor < 1) { + keyObj = keyObjV4.DeliveryServiceSSLKeysV15 } else { + keyObj = keyObjV4 + } + + if len(alerts.Alerts) == 0 { + api.WriteResp(w, r, keyObj) + } else { + api.WriteAlertsObj(w, r, http.StatusOK, alerts, keyObj) + } +} + +func getSslKeys(inf *api.APIInfo, ctx context.Context) (tc.DeliveryServiceSSLKeysV4, error) { + xmlID := inf.Params["xmlid"] + version := inf.Params["version"] + decode := inf.Params["decode"] + + keyObjFromTv, ok, err := inf.Vault.GetDeliveryServiceSSLKeys(xmlID, version, inf.Tx.Tx, ctx) + if err != nil { + return tc.DeliveryServiceSSLKeysV4{}, errors.New("getting ssl keys: " + err.Error()) + } + keyObj := tc.DeliveryServiceSSLKeysV4{} + if ok { + keyObj.DeliveryServiceSSLKeysV15 = keyObjFromTv parsedCert := keyObj.Certificate err = Base64DecodeCertificate(&parsedCert) if err != nil { - userErr := api.LogErr(r, http.StatusInternalServerError, nil, errors.New("getting SSL keys for XMLID '"+xmlID+"': "+err.Error())) - alerts.AddNewAlert(tc.ErrorLevel, userErr.Error()) - api.WriteAlerts(w, r, http.StatusInternalServerError, alerts) - return + return tc.DeliveryServiceSSLKeysV4{}, errors.New("getting SSL keys for XMLID '" + xmlID + "': " + err.Error()) } if decode != "" && decode != "0" { // the Perl version checked the decode string as: if ( $decode ) keyObj.Certificate = parsedCert } if keyObj.Certificate.Crt != "" && keyObj.Expiration.IsZero() { - exp, err := parseExpirationFromCert([]byte(parsedCert.Crt)) + exp, sans, err := parseExpirationAndSansFromCert([]byte(parsedCert.Crt), keyObj.Hostname) if err != nil { - userErr := api.LogErr(r, http.StatusInternalServerError, nil, errors.New(xmlID+": "+err.Error())) - alerts.AddNewAlert(tc.ErrorLevel, userErr.Error()) - api.WriteAlerts(w, r, http.StatusInternalServerError, alerts) - return + return tc.DeliveryServiceSSLKeysV4{}, errors.New(xmlID + ": " + err.Error()) } keyObj.Expiration = exp + keyObj.Sans = sans } } - if len(alerts.Alerts) == 0 { - api.WriteResp(w, r, keyObj) - } else { - api.WriteAlertsObj(w, r, http.StatusOK, alerts, keyObj) - } + return keyObj, nil } -func parseExpirationFromCert(cert []byte) (time.Time, error) { +func parseExpirationAndSansFromCert(cert []byte, commonName string) (time.Time, []string, error) { block, _ := pem.Decode(cert) if block == nil { - return time.Time{}, errors.New("Error decoding cert to parse expiration") + return time.Time{}, []string{}, errors.New("Error decoding cert to parse expiration") } x509cert, err := x509.ParseCertificate(block.Bytes) if err != nil { - return time.Time{}, errors.New("Error parsing cert to get expiration - " + err.Error()) + return time.Time{}, []string{}, errors.New("Error parsing cert to get expiration - " + err.Error()) } - return x509cert.NotAfter, nil + dnsNames := util.RemoveStrFromArray(x509cert.DNSNames, commonName) + + return x509cert.NotAfter, dnsNames, nil } func Base64DecodeCertificate(cert *tc.DeliveryServiceSSLKeysCertificate) error { diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go b/traffic_ops/traffic_ops_golang/routing/routes.go index b8a3fc6e27..8c3ccf03ef 100644 --- a/traffic_ops/traffic_ops_golang/routing/routes.go +++ b/traffic_ops/traffic_ops_golang/routing/routes.go @@ -130,6 +130,9 @@ func Routes(d ServerData) ([]Route, http.Handler, error) { * 4.x API */ + // SSL Keys + {api.Version{Major: 4, Minor: 1}, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLID, auth.PrivLevelAdmin, nil, Authenticated, nil, 41357729074}, + // CDN lock {api.Version{Major: 4, Minor: 0}, http.MethodGet, `cdn_locks/?$`, cdn_lock.Read, auth.PrivLevelReadOnly, nil, Authenticated, nil, 4134390561}, {api.Version{Major: 4, Minor: 0}, http.MethodPost, `cdn_locks/?$`, cdn_lock.Create, auth.PrivLevelOperations, nil, Authenticated, nil, 4134390562}, @@ -484,7 +487,7 @@ func Routes(d ServerData) ([]Route, http.Handler, error) { {api.Version{Major: 4, Minor: 0}, http.MethodDelete, `deliveryservices/{id}/?$`, api.DeleteHandler(&deliveryservice.TODeliveryService{}), auth.PrivLevelOperations, nil, Authenticated, nil, 4226420743}, {api.Version{Major: 4, Minor: 0}, http.MethodGet, `deliveryservices/{id}/servers/eligible/?$`, deliveryservice.GetServersEligible, auth.PrivLevelReadOnly, nil, Authenticated, nil, 4747615843}, - {api.Version{Major: 4, Minor: 0}, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLIDV15, auth.PrivLevelAdmin, nil, Authenticated, nil, 41357729073}, + {api.Version{Major: 4, Minor: 0}, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLID, auth.PrivLevelAdmin, nil, Authenticated, nil, 41357729073}, {api.Version{Major: 4, Minor: 0}, http.MethodPost, `deliveryservices/sslkeys/add$`, deliveryservice.AddSSLKeys, auth.PrivLevelAdmin, nil, Authenticated, nil, 48728785833}, {api.Version{Major: 4, Minor: 0}, http.MethodDelete, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.DeleteSSLKeys, auth.PrivLevelOperations, nil, Authenticated, nil, 49267343}, {api.Version{Major: 4, Minor: 0}, http.MethodPost, `deliveryservices/sslkeys/generate/?$`, deliveryservice.GenerateSSLKeys, auth.PrivLevelOperations, nil, Authenticated, nil, 4534390513}, @@ -872,7 +875,7 @@ func Routes(d ServerData) ([]Route, http.Handler, error) { {api.Version{Major: 3, Minor: 0}, http.MethodDelete, `deliveryservices/{id}/?$`, api.DeleteHandler(&deliveryservice.TODeliveryService{}), auth.PrivLevelOperations, nil, Authenticated, nil, 2226420743}, {api.Version{Major: 3, Minor: 0}, http.MethodGet, `deliveryservices/{id}/servers/eligible/?$`, deliveryservice.GetServersEligible, auth.PrivLevelReadOnly, nil, Authenticated, nil, 2747615843}, - {api.Version{Major: 3, Minor: 0}, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLIDV15, auth.PrivLevelAdmin, nil, Authenticated, nil, 21357729073}, + {api.Version{Major: 3, Minor: 0}, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLID, auth.PrivLevelAdmin, nil, Authenticated, nil, 21357729073}, {api.Version{Major: 3, Minor: 0}, http.MethodPost, `deliveryservices/sslkeys/add$`, deliveryservice.AddSSLKeys, auth.PrivLevelAdmin, nil, Authenticated, nil, 28728785833}, {api.Version{Major: 3, Minor: 0}, http.MethodDelete, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.DeleteSSLKeys, auth.PrivLevelOperations, nil, Authenticated, nil, 29267343}, {api.Version{Major: 3, Minor: 0}, http.MethodPost, `deliveryservices/sslkeys/generate/?$`, deliveryservice.GenerateSSLKeys, auth.PrivLevelOperations, nil, Authenticated, nil, 2534390513}, @@ -1236,7 +1239,7 @@ func Routes(d ServerData) ([]Route, http.Handler, error) { {api.Version{Major: 2, Minor: 0}, http.MethodDelete, `deliveryservices/{id}/?$`, api.DeleteHandler(&deliveryservice.TODeliveryService{}), auth.PrivLevelOperations, nil, Authenticated, nil, 222642074}, {api.Version{Major: 2, Minor: 0}, http.MethodGet, `deliveryservices/{id}/servers/eligible/?$`, deliveryservice.GetServersEligible, auth.PrivLevelReadOnly, nil, Authenticated, nil, 274761584}, - {api.Version{Major: 2, Minor: 0}, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLIDV15, auth.PrivLevelAdmin, nil, Authenticated, nil, 2135772907}, + {api.Version{Major: 2, Minor: 0}, http.MethodGet, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLID, auth.PrivLevelAdmin, nil, Authenticated, nil, 2135772907}, {api.Version{Major: 2, Minor: 0}, http.MethodPost, `deliveryservices/sslkeys/add$`, deliveryservice.AddSSLKeys, auth.PrivLevelAdmin, nil, Authenticated, nil, 2872878583}, {api.Version{Major: 2, Minor: 0}, http.MethodDelete, `deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.DeleteSSLKeys, auth.PrivLevelOperations, nil, Authenticated, nil, 2926734}, {api.Version{Major: 2, Minor: 0}, http.MethodPost, `deliveryservices/sslkeys/generate/?$`, deliveryservice.GenerateSSLKeys, auth.PrivLevelOperations, nil, Authenticated, nil, 253439051}, diff --git a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js index 59596aff74..205b30399e 100644 --- a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js +++ b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/FormDeliveryServiceSslKeysController.js @@ -65,6 +65,7 @@ var FormDeliveryServiceSslKeysController = function(deliveryService, sslKeys, $s $scope.navigateToPath = locationUtils.navigateToPath; $scope.formattedExpiration = $scope.sslKeys.expiration !== undefined ? $filter('date')($scope.sslKeys.expiration, 'MM/dd/yyyy') : undefined; + $scope.sans = $scope.sslKeys.sans !== undefined ? sslKeys.sans.join(', ') : "" $scope.generateKeys = function() { locationUtils.navigateToPath('/delivery-services/' + deliveryService.id + '/ssl-keys/generate'); diff --git a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html index 6f0bf3a6ca..489491851e 100644 --- a/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html +++ b/traffic_portal/app/src/common/modules/form/deliveryServiceSslKeys/form.deliveryServiceSslKeys.tpl.html @@ -61,6 +61,12 @@ +