Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implementing certificate expiry detail in security dashboard #3000

Merged
merged 15 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 37 additions & 37 deletions cmd/collectors/rest/plugins/certificate/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ func (my *Certificate) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix,
var (
adminVserver string
adminVserverSerial string
expiryTimeMetric *matrix.Metric
unixTime time.Time
err error
)
data := dataMap[my.Object]
Expand Down Expand Up @@ -85,22 +87,33 @@ func (my *Certificate) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix,
return nil, nil, nil
}

// update certificate instance based on admin vaserver serial
// update certificate instance based on admin vserver serial
for _, certificateInstance := range data.GetInstances() {
if certificateInstance.IsExportable() {
certificateInstance.SetExportable(false)
serialNumber := certificateInstance.GetLabel("serial_number")

if serialNumber == adminVserverSerial {
certificateInstance.SetExportable(true)
// Admin SVM certificate is cluster scoped, but the REST API does not return the SVM name in its response. Add here for ZAPI parity
certificateInstance.SetLabel("svm", adminVserver)
my.setCertificateIssuerType(certificateInstance)
my.setCertificateValidity(data, certificateInstance)
}
if !certificateInstance.IsExportable() {
continue
}
serialNumber := certificateInstance.GetLabel("serial_number")
certType := certificateInstance.GetLabel("type")

if expiryTimeMetric = data.GetMetric("expiration"); expiryTimeMetric == nil {
my.Logger.Error().Stack().Msg("missing expiry time metric")
continue
}
}

if expiryTime, ok := expiryTimeMetric.GetValueFloat64(certificateInstance); ok {
// convert expiryTime from float64 to int64 and then to unix Time
unixTime = time.Unix(int64(expiryTime), 0)
certificateInstance.SetLabel("expiry_time", unixTime.UTC().Format(time.RFC3339))
} else {
// This is fail-safe case
unixTime = time.Now()
}

if serialNumber == adminVserverSerial && certType == "server" {
my.setCertificateIssuerType(certificateInstance)
my.setCertificateValidity(unixTime, certificateInstance)
}
}
}

my.currentVal++
Expand Down Expand Up @@ -147,36 +160,23 @@ func (my *Certificate) setCertificateIssuerType(instance *matrix.Instance) {
}
}

func (my *Certificate) setCertificateValidity(data *matrix.Matrix, instance *matrix.Instance) {
var (
expiryTimeMetric *matrix.Metric
)

func (my *Certificate) setCertificateValidity(unixTime time.Time, instance *matrix.Instance) {
instance.SetLabel("certificateExpiryStatus", "unknown")

if expiryTimeMetric = data.GetMetric("expiry_time"); expiryTimeMetric == nil {
my.Logger.Error().Stack().Msg("missing expiry time metric")
return
}

if expiryTime, ok := expiryTimeMetric.GetValueFloat64(instance); ok {
// convert expiryTime from float64 to int64 and find difference

timestampDiff := time.Until(time.Unix(int64(expiryTime), 0)).Hours()
// find difference from unix Time
timestampDiff := time.Until(unixTime).Hours()

if timestampDiff <= 0 {
instance.SetLabel("certificateExpiryStatus", "expired")
if timestampDiff <= 0 {
instance.SetLabel("certificateExpiryStatus", "expired")
} else {
// daysRemaining will be more than 0 if it has reached this point, convert to days
daysRemaining := timestampDiff / 24
if daysRemaining < 60 {
instance.SetLabel("certificateExpiryStatus", "expiring")
} else {
// daysRemaining will be more than 0 if it has reached this point, convert to days
daysRemaining := timestampDiff / 24
if daysRemaining < 60 {
instance.SetLabel("certificateExpiryStatus", "expiring")
} else {
instance.SetLabel("certificateExpiryStatus", "active")
}
instance.SetLabel("certificateExpiryStatus", "active")
}
}

}

func (my *Certificate) GetAdminVserver() (string, error) {
Expand Down
73 changes: 39 additions & 34 deletions cmd/collectors/zapi/plugins/certificate/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ func (my *Certificate) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix,
var (
adminVserver string
adminVserverSerial string
expiryTimeMetric *matrix.Metric
unixTime time.Time
err error
)

Expand Down Expand Up @@ -96,20 +98,35 @@ func (my *Certificate) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix,
return nil, nil, nil
}

// update certificate instance based on admin vaserver serial
// update certificate instance based on admin vserver serial
for certificateInstanceKey, certificateInstance := range data.GetInstances() {
if certificateInstance.IsExportable() {
certificateInstance.SetExportable(false)
serialNumber := certificateInstance.GetLabel("serial_number")

if serialNumber == adminVserverSerial {
certificateInstance.SetExportable(true)
my.setCertificateIssuerType(certificateInstance, certificateInstanceKey)
my.setCertificateValidity(data, certificateInstance)
}
if !certificateInstance.IsExportable() {
continue
}
name := certificateInstance.GetLabel("name")
serialNumber := certificateInstance.GetLabel("serial_number")
svm := certificateInstance.GetLabel("svm")
certType := certificateInstance.GetLabel("type")
certificateInstance.SetLabel("uuid", name+serialNumber+svm)

if expiryTimeMetric = data.GetMetric("certificate-info.expiration-date"); expiryTimeMetric == nil {
my.Logger.Error().Msg("missing expiry time metric")
continue
}
if expiryTime, ok := expiryTimeMetric.GetValueFloat64(certificateInstance); ok {
// convert expiryTime from float64 to int64 and then to unix Time
unixTime = time.Unix(int64(expiryTime), 0)
certificateInstance.SetLabel("expiry_time", unixTime.UTC().Format(time.RFC3339))
} else {
// This is fail-safe case
unixTime = time.Now()
}
}

if serialNumber == adminVserverSerial && certType == "server" {
my.setCertificateIssuerType(certificateInstance, certificateInstanceKey)
my.setCertificateValidity(unixTime, certificateInstance)
}
}
}

my.currentVal++
Expand Down Expand Up @@ -155,35 +172,23 @@ func (my *Certificate) setCertificateIssuerType(instance *matrix.Instance, certi
}
}

func (my *Certificate) setCertificateValidity(data *matrix.Matrix, instance *matrix.Instance) {
var (
expiryTimeMetric *matrix.Metric
)

func (my *Certificate) setCertificateValidity(unixTime time.Time, instance *matrix.Instance) {
instance.SetLabel("certificateExpiryStatus", "unknown")

if expiryTimeMetric = data.GetMetric("certificate-info.expiration-date"); expiryTimeMetric == nil {
my.Logger.Error().Msg("missing expiry time metric")
return
}

if expiryTime, ok := expiryTimeMetric.GetValueFloat64(instance); ok {
// convert expiryTime from float64 to int64 and find difference
timestampDiff := time.Until(time.Unix(int64(expiryTime), 0)).Hours()
// find difference from unix Time
timestampDiff := time.Until(unixTime).Hours()

if timestampDiff <= 0 {
instance.SetLabel("certificateExpiryStatus", "expired")
if timestampDiff <= 0 {
instance.SetLabel("certificateExpiryStatus", "expired")
} else {
// daysRemaining will be more than 0 if it has reached this point, convert to days
daysRemaining := timestampDiff / 24
if daysRemaining < 60 {
instance.SetLabel("certificateExpiryStatus", "expiring")
} else {
// daysRemaining will be more than 0 if it has reached this point, convert to days
daysRemaining := timestampDiff / 24
if daysRemaining < 60 {
instance.SetLabel("certificateExpiryStatus", "expiring")
} else {
instance.SetLabel("certificateExpiryStatus", "active")
}
instance.SetLabel("certificateExpiryStatus", "active")
}
}

}

func (my *Certificate) GetAdminVserver() (string, error) {
Expand Down
25 changes: 14 additions & 11 deletions conf/rest/9.12.0/security_certificate.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@

name: SecurityCert
query: api/security/certificates
query: api/private/cli/security/certificate
object: security_certificate

counters:
- ^^uuid
- ^name
- ^public_certificate => certificatePEM
- ^scope => scope
- ^serial_number => serial_number
- ^svm.name => svm
- ^cert_name => name
- ^public_cert => certificatePEM
- ^serial => serial_number
- ^type => type
- expiry_time(timestamp) => expiry_time
- filter:
- scope=!"svm"
- type="server"
- ^vserver => svm
- expiration(timestamp) => expiry_time

#endpoints:
# - query: api/security/certificates
# counters:
# - ^^uuid
# - ^scope => scope

plugins:
- Certificate:
Expand All @@ -27,8 +29,9 @@ export_options:
instance_labels:
- certificateExpiryStatus
- certificateIssuerType
- expiry_time
- name
- scope
# - scope
- serial_number
- svm
- type
11 changes: 5 additions & 6 deletions conf/zapi/cdot/9.8.0/security_certificate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ counters:
- expiration-date => expiry_time

plugins:
- LabelAgent:
include_equals:
- type `server`
- Certificate:
schedule:
- data: 3m # should be multiple of data poll duration

export_options:
instance_keys:
- name
- serial_number
- svm
- uuid
instance_labels:
- certificateExpiryStatus
- certificateIssuerType
- expiry_time
- name
- serial_number
- svm
- type
21 changes: 20 additions & 1 deletion container/prometheus/alert_rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,23 @@ groups:
severity: "warning"
annotations:
summary: "{{ $labels.object }} [{{ $labels.volume }}] deleted"
description: "{{ $labels.object }} [{{ $labels.volume }}] deleted"
description: "{{ $labels.object }} [{{ $labels.volume }}] deleted"

# Certificates expiring within 1 month
- alert: Certificates expiring within 1 month
expr: 0 < (security_certificate_expiry_time{} - time()) < (30*24*3600)
for: 1m
labels:
severity: "warning"
annotations:
summary: "Certificate [{{ $labels.name }}] will be expiring on [{{ $labels.expiry_time }}]"
description: "Certificate [{{ $labels.name }}] will be expiring on [{{ $labels.expiry_time }}]"

# Certificates expired
- alert: Certificates expired
expr: (security_certificate_expiry_time{} - time()) < 0
labels:
severity: "critical"
annotations:
summary: "Certificate [{{ $labels.name }}] has been expired on [{{ $labels.expiry_time }}]"
description: "Certificate [{{ $labels.name }}] has been expired on [{{ $labels.expiry_time }}]"
Loading