fix: fix cluster compliance query for security account and banner checks - #4366
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the ONTAP Security Grafana dashboard’s “cluster compliance” PromQL so the security-account unlocked check and login-banner-related checks behave correctly across cluster/SVM selections.
Changes:
- Refines the unlocked-account compliance check to target the built-in
adminaccount (role_name="admin", user_name="admin"). - Reworks the login/banner portion of the compliance queries using an
unlessclause to better detect missing login-message series for selected SVMs. - Applies the updated compliance query logic consistently across the dashboard’s stat/pie/table panels.
Comments suppressed due to low confidence (2)
grafana/dashboards/cmode/security.json:883
- Same issue as panel 214: the
unlessjoin ison (svm)but Cluster/Datacenter variables are multi-select, so SVM-name collisions across clusters can cause incorrect results. Useunless on (datacenter, cluster, svm)so matching is scoped to the selected cluster/datacenter.
"expr": "count(\n group by (datacenter, cluster) (\n support_labels{asup_enabled=\"true\",asup_https_configured!=\"https\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",telnet_enabled=\"true\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",rsh_enabled=\"true\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",hash_algorithm=\"md5\"}\n )\n \u003e\n 0\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"\"}\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"none\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",locked=\"false\",role_name=\"admin\",user_name=\"admin\"}\n )\n \u003e\n 0\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"cluster\"}\n or\n count by (datacenter, cluster) (ntpserver_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}) \u003c 1\n or\n security_audit_destination_status{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",protocol!=\"tcp_encrypted\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",fips_enabled=\"false\"}\n or\n svm_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\",type=\"admin\"}\n or\n group by (datacenter, cluster) (\n (\n (\n svm_labels{cifs_protocol_enabled=\"true\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n or\n svm_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",nfs_protocol_enabled=\"true\",svm=~\"$SVM\"}\n )\n and\n svm_labels{audit_protocol_enabled=\"false\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n )\n or\n security_ssh_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"svm\"}\n or\n (\n svm_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n unless on (svm)\n security_login_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm!=\"$Cluster\",svm=~\"$SVM\"}\n )\n )\n )\n )\nor\n vector(0)",
grafana/dashboards/cmode/security.json:4260
- The
unlessmatch is scoped only tosvm, but this dashboard allows multi-select Cluster/Datacenter and the same SVM name can appear in multiple clusters. Usingunless on (svm)can therefore suppress missingsecurity_login_labelsfor one cluster because another cluster has the same SVM name. Match on(datacenter, cluster, svm)to avoid cross-cluster collisions.
"expr": "group by (datacenter, cluster) (\n support_labels{asup_enabled=\"true\",asup_https_configured!=\"https\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",telnet_enabled=\"true\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",rsh_enabled=\"true\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",hash_algorithm=\"md5\"}\n )\n \u003e\n 0\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"\"}\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"none\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",locked=\"false\",role_name=\"admin\",user_name=\"admin\"}\n )\n \u003e\n 0\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"cluster\"}\n or\n count by (datacenter, cluster) (ntpserver_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}) \u003c 1\n or\n security_audit_destination_status{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",protocol!=\"tcp_encrypted\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",fips_enabled=\"false\"}\n or\n svm_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\",type=\"admin\"}\n or\n group by (datacenter, cluster) (\n (\n (\n svm_labels{cifs_protocol_enabled=\"true\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n or\n svm_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",nfs_protocol_enabled=\"true\",svm=~\"$SVM\"}\n )\n and\n svm_labels{audit_protocol_enabled=\"false\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n )\n or\n security_ssh_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"svm\"}\n or\n (\n svm_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n unless on (svm)\n security_login_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm!=\"$Cluster\",svm=~\"$SVM\"}\n )\n or\n sum by (datacenter, cluster) (\n volume_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",root_volume=\"No\",snapshot_policy=\"none\"}\n )\n \u003e\n 0\n or\n sum by (datacenter, cluster) (\n volume_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",root_volume=\"No\",snapshot_autodelete=\"true\"}\n )\n \u003e\n 0\n or\n sum by (datacenter, cluster) (\n svm_labels{anti_ransomware_state=~\"|.*disabled\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n )\n \u003e\n 0\n or\n volume_arw_status{ArwStatus!=\"Active Mode\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n * on (instance) group_left ()\n metadata_collector_instances{collector=\"Rest\",datacenter=~\"$Datacenter\",object=\"Volume\"}\n or\n count by (datacenter, cluster) (\n ems_destination_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n )\n \u003e\n 0\n or\n support_auto_update_labels{auto_update_enabled=\"false\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n )\n)",
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ecc49e4 to
9811c99
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
grafana/dashboards/cmode/security.json:883
- Same issue as the earlier cluster compliance expression: the SVM login-banner check only matches
security_login_labelswithscope="svm". If the exporter sometimes omits thescopelabel (as accounted for elsewhere in this dashboard viasvm!="$Cluster"), SVMs with an empty banner could be missed.
Recommend adding an or security_login_labels{banner="",...,svm!="$Cluster",svm=~"$SVM"} fallback alongside the scope="svm" clause.
"expr": "count(\n group by (datacenter, cluster) (\n support_labels{asup_enabled=\"true\",asup_https_configured!=\"https\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",telnet_enabled=\"true\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",rsh_enabled=\"true\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",hash_algorithm=\"md5\"}\n )\n \u003e\n 0\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"\"}\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"none\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",locked=\"false\",role_name=\"admin\",user_name=\"admin\"}\n )\n \u003e\n 0\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"cluster\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$Cluster\"}\n or\n count by (datacenter, cluster) (ntpserver_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}) \u003c 1\n or\n security_audit_destination_status{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",protocol!=\"tcp_encrypted\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",fips_enabled=\"false\"}\n or\n svm_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\",type=\"admin\"}\n or\n group by (datacenter, cluster) (\n (\n (\n svm_labels{cifs_protocol_enabled=\"true\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n or\n svm_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",nfs_protocol_enabled=\"true\",svm=~\"$SVM\"}\n )\n and\n svm_labels{audit_protocol_enabled=\"false\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n )\n or\n security_ssh_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"svm\",svm=~\"$SVM\"}\n )\n )\n )\nor\n vector(0)",
grafana/dashboards/cmode/security.json:4260
- This table/query variant of the cluster compliance logic also only checks SVM login-banner emptiness via
security_login_labels{...,scope="svm",svm=~"$SVM"}. If SVM login-message series can exist without ascopelabel (as handled elsewhere withsvm!="$Cluster"), empty-banner SVMs could be missed here.
Suggest adding a fallback or security_login_labels{banner="",...,svm!="$Cluster",svm=~"$SVM"} near the existing scope="svm" clause.
"expr": "group by (datacenter, cluster) (\n support_labels{asup_enabled=\"true\",asup_https_configured!=\"https\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",telnet_enabled=\"true\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",rsh_enabled=\"true\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",hash_algorithm=\"md5\"}\n )\n \u003e\n 0\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"\"}\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"none\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",locked=\"false\",role_name=\"admin\",user_name=\"admin\"}\n )\n \u003e\n 0\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"cluster\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$Cluster\"}\n or\n count by (datacenter, cluster) (ntpserver_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}) \u003c 1\n or\n security_audit_destination_status{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",protocol!=\"tcp_encrypted\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",fips_enabled=\"false\"}\n or\n svm_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\",type=\"admin\"}\n or\n group by (datacenter, cluster) (\n (\n (\n svm_labels{cifs_protocol_enabled=\"true\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n or\n svm_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",nfs_protocol_enabled=\"true\",svm=~\"$SVM\"}\n )\n and\n svm_labels{audit_protocol_enabled=\"false\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n )\n or\n security_ssh_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"svm\",svm=~\"$SVM\"}\n or\n sum by (datacenter, cluster) (\n volume_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",root_volume=\"No\",snapshot_policy=\"none\"}\n )\n \u003e\n 0\n or\n sum by (datacenter, cluster) (\n volume_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",root_volume=\"No\",snapshot_autodelete=\"true\"}\n )\n \u003e\n 0\n or\n sum by (datacenter, cluster) (\n svm_labels{anti_ransomware_state=~\"|.*disabled\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n )\n \u003e\n 0\n or\n volume_arw_status{ArwStatus!=\"Active Mode\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n * on (instance) group_left ()\n metadata_collector_instances{collector=\"Rest\",datacenter=~\"$Datacenter\",object=\"Volume\"}\n or\n count by (datacenter, cluster) (\n ems_destination_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n )\n \u003e\n 0\n or\n support_auto_update_labels{auto_update_enabled=\"false\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n )\n)",
grafana/dashboards/cmode/security.json:215
- The SVM login-banner noncompliance check only matches
security_login_labelsseries withscope="svm". Elsewhere in this dashboard (e.g. the SVM login-message table query) you also handle SVM records that don’t have ascopelabel by matchingsvm!="$Cluster". If those scope-less series can occur here too, an empty banner on an SVM could be missed and the cluster incorrectly marked compliant.
Consider OR-ing in the scope-less variant with the same banner="" filter (e.g. add or security_login_labels{banner="",...,svm!="$Cluster",svm=~"$SVM"} next to the existing scope="svm" clause).
This issue also appears in the following locations of the same file:
- line 883
- line 4260
"expr": "count(\n group by (datacenter, cluster) (\n support_labels{asup_enabled=\"true\",asup_https_configured!=\"https\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",telnet_enabled=\"true\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",rsh_enabled=\"true\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",hash_algorithm=\"md5\"}\n )\n \u003e\n 0\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"\"}\n or\n cluster_peer_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",encryption_state=\"none\"}\n or\n group by (datacenter, cluster) (\n security_account_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",locked=\"false\",role_name=\"admin\",user_name=\"admin\"}\n )\n \u003e\n 0\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"cluster\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$Cluster\"}\n or\n count by (datacenter, cluster) (ntpserver_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}) \u003c 1\n or\n security_audit_destination_status{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",protocol!=\"tcp_encrypted\"}\n or\n security_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",fips_enabled=\"false\"}\n or\n svm_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\",type=\"admin\"}\n or\n group by (datacenter, cluster) (\n (\n (\n svm_labels{cifs_protocol_enabled=\"true\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n or\n svm_labels{cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",nfs_protocol_enabled=\"true\",svm=~\"$SVM\"}\n )\n and\n svm_labels{audit_protocol_enabled=\"false\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",svm=~\"$SVM\"}\n )\n or\n security_ssh_labels{ciphers=~\".*_cbc.*\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\"}\n or\n security_login_labels{banner=\"\",cluster=~\"$Cluster\",datacenter=~\"$Datacenter\",scope=\"svm\",svm=~\"$SVM\"}\n )\n )\n )\nor\n vector(0)",
Locked account check – bug. It currently flags a cluster as non-compliant if any local account is unlocked, but it should only check the built-in admin account (per the "Default Admin User" rule). Regular users being unlocked is normal. security_account_labels metrics
security_login_labels – used in 2 places in this check:
Login banner check (banner="") – correct, no issue.
A second, unconditioned clause that just checks if the metric exists (no banner filter) – this matches almost always since ONTAP always returns a login-message record, so it incorrectly contributes to non-compliance regardless of actual banner status. This is the bug.