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 8 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
2 changes: 0 additions & 2 deletions cmd/collectors/rest/plugins/certificate/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,9 @@ func (my *Certificate) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix,
// update certificate instance based on admin vaserver 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)
Expand Down
2 changes: 0 additions & 2 deletions cmd/collectors/zapi/plugins/certificate/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,9 @@ func (my *Certificate) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix,
// update certificate instance based on admin vaserver 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)
}
Expand Down
5 changes: 2 additions & 3 deletions conf/rest/9.12.0/security_certificate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ object: security_certificate

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

plugins:
- Certificate:
Expand All @@ -23,6 +21,7 @@ plugins:

export_options:
instance_keys:
- expiry_time
- uuid
instance_labels:
- certificateExpiryStatus
Expand Down
4 changes: 1 addition & 3 deletions conf/zapi/cdot/9.8.0/security_certificate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ counters:
- expiration-date => expiry_time

plugins:
- LabelAgent:
include_equals:
- type `server`
- Certificate:
schedule:
- data: 3m # should be multiple of data poll duration
Expand All @@ -28,4 +25,5 @@ export_options:
instance_labels:
- certificateExpiryStatus
- certificateIssuerType
- expiry_time
- 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 < (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: (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 }}]"
250 changes: 246 additions & 4 deletions grafana/dashboards/cmode/security.json
Original file line number Diff line number Diff line change
Expand Up @@ -1900,14 +1900,256 @@
],
"type": "stat"
},
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this dashboard, root SVMs are excluded by default. Are we sure that root SVM certificates also need to be excluded for certificates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, While checking the security/certificates Rest call, there are no certificates records for root svms. We are good to go here.

Also, I would be adding the scope field, which shows cluster or svm to help customer to see the scope of the certificate.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying:
a) that root SVMs do not have certificates or
b) that ONTAP does not return certificates for root SVMs

I think you're saying that root SVM have certificates, but ONTAP is not returning them? If that's the case, we should check the expiry for root SVM certificates some other way

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there is little correction on my above note.

  • Out of admin and node svm (which we treat as root svm), admin svm can have certificates
  • But, It's cluster scope and not svm scope, (scope is only in Rest) which means we don't get svm name in certificate in Rest calls.
  • We would do little more work to get those detail in Rest, which we are already doing in existing plugin, and we have this comment as well for that reference.
    // Admin SVM certificate is cluster scoped, but the REST API does not return the SVM name in its response. Add here for ZAPI parity
  • As there are cluster scoped and svm scoped certificates in table, I need to remove the svm filter from query,
    So, even the SVM drop down have limited svms but this table shows certificates from all of them.
    Screenshot from .127 system
image

Just to note, Above the table the stats count is showing those admin svm's certificates only(admin svm is unique in cluster) and not all of them.

"datasource": "${DS_PROMETHEUS}",
"description": "This panel requires Harvest REST collector.\n\nThis panel displays Certificate expiration time.",
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "transparent",
"mode": "fixed"
},
"custom": {
"align": "left",
"displayMode": "color-background-solid",
"filterable": true
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": ""
}
]
},
"unit": "locale"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "Expires In"
},
"properties": [
{
"id": "unit",
"value": "dateTimeFromNow"
}
]
},
{
"matcher": {
"id": "byName",
"options": "svm"
},
"properties": [
{
"id": "displayName",
"value": "SVM"
},
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "",
"url": "/d/cdot-svm/ontap-svm?orgId=1&${Datacenter:queryparam}&${Cluster:queryparam}&${__url_time_range}&var-SVM=${__value.raw}"
}
]
}
]
},
{
"matcher": {
"id": "byName",
"options": "Expiry"
},
"properties": [
{
"id": "mappings",
"value": [
{
"options": {
"from": -100000000000000000000,
"result": {
"color": "red",
"index": 0,
"text": "Expired"
},
"to": 0
},
"type": "range"
},
{
"options": {
"from": 0,
"result": {
"color": "orange",
"index": 1,
"text": "This Month"
},
"to": 2678400
},
"type": "range"
},
{
"options": {
"from": 2678400,
"result": {
"color": "green",
"index": 2,
"text": "OK"
},
"to": 100000000000000000000
},
"type": "range"
}
]
}
]
},
{
"matcher": {
"id": "byName",
"options": "Expiry Date"
},
"properties": [
{
"id": "custom.width",
"value": 204
}
]
}
]
},
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 26
},
"id": 228,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": [
{
"desc": false,
"displayName": "Expiry"
}
]
},
"pluginVersion": "8.3.4",
"targets": [
{
"datasource": "${DS_PROMETHEUS}",
"editorMode": "code",
"exemplar": false,
"expr": "security_certificate_labels{datacenter=~\"$Datacenter\", cluster=~\"$Cluster\"}",
"format": "table",
"hide": false,
"instant": true,
"interval": "",
"legendFormat": "",
"refId": "A"
},
{
"datasource": "${DS_PROMETHEUS}",
"exemplar": false,
"expr": "security_certificate_expiry_time{datacenter=~\"$Datacenter\", cluster=~\"$Cluster\"}-time()",
"format": "table",
"hide": false,
"instant": true,
"interval": "",
"legendFormat": "",
"refId": "B"
}
],
"title": "SSL Certificates Expiration",
"transformations": [
{
"id": "seriesToColumns",
"options": {
"byField": "expiry_time"
}
},
{
"id": "filterFieldsByName",
"options": {
"include": {
"names": [
"expiry_time",
"scope",
"svm",
"type",
"Value #B"
]
}
}
},
{
"id": "calculateField",
"options": {
"alias": "Expiry Date",
"mode": "reduceRow",
"reduce": {
"include": [
"expiry_time"
],
"reducer": "last"
}
}
},
{
"id": "organize",
"options": {
"excludeByName": {
"Value #B": false
},
"includeByName": {},
"indexByName": {
"Expiry Date": 3,
"Value #B": 4,
"expiry_time": 5,
"scope": 2,
"svm": 0,
"type": 1
},
"renameByName": {
"Expiry Date": "",
"Value #B": "Expiry",
"expiry_time": "Expires In",
"name": "Certificate Name",
"scope": "Scope",
"type": "Type"
}
}
}
],
"type": "table"
},
{
"collapsed": true,
"datasource": "${DS_PROMETHEUS}",
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 26
"y": 33
},
"id": 12,
"panels": [
Expand Down Expand Up @@ -2253,7 +2495,7 @@
"h": 1,
"w": 24,
"x": 0,
"y": 29
"y": 36
},
"id": 223,
"panels": [
Expand Down Expand Up @@ -3587,7 +3829,7 @@
},
{
"exemplar": false,
"expr": "security_certificate_labels{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\"}",
"expr": "security_certificate_labels{datacenter=~\"$Datacenter\",cluster=~\"$Cluster\",certificateExpiryStatus!=\"\",certificateIssuerType!=\"\"}",
"format": "table",
"hide": false,
"instant": true,
Expand Down Expand Up @@ -3830,7 +4072,7 @@
"h": 1,
"w": 24,
"x": 0,
"y": 30
"y": 37
},
"id": 227,
"panels": [
Expand Down