Skip to content

Commit

Permalink
Merge pull request #895 from akrauza/ADCS
Browse files Browse the repository at this point in the history
Add Collector for Active Directory Certificate Services (ADCS)
  • Loading branch information
breed808 authored Jan 2, 2022
2 parents d9f4264 + a89b537 commit 746158d
Show file tree
Hide file tree
Showing 5 changed files with 310 additions and 4 deletions.
242 changes: 242 additions & 0 deletions collector/adcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
//go:build windows
// +build windows

package collector

import (
"errors"
"github.com/prometheus-community/windows_exporter/log"
"github.com/prometheus/client_golang/prometheus"
"strings"
)

func init() {
registerCollector("adcs", adcsCollectorMethod, "Certification Authority")
}

type adcsCollector struct {
RequestsPerSecond *prometheus.Desc
RequestProcessingTime *prometheus.Desc
RetrievalsPerSecond *prometheus.Desc
RetrievalProcessingTime *prometheus.Desc
FailedRequestsPerSecond *prometheus.Desc
IssuedRequestsPerSecond *prometheus.Desc
PendingRequestsPerSecond *prometheus.Desc
RequestCryptographicSigningTime *prometheus.Desc
RequestPolicyModuleProcessingTime *prometheus.Desc
ChallengeResponsesPerSecond *prometheus.Desc
ChallengeResponseProcessingTime *prometheus.Desc
SignedCertificateTimestampListsPerSecond *prometheus.Desc
SignedCertificateTimestampListProcessingTime *prometheus.Desc
}

// ADCSCollectorMethod ...
func adcsCollectorMethod() (Collector, error) {
const subsystem = "adcs"
return &adcsCollector{
RequestsPerSecond: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "requests_total"),
"Total certificate requests processed",
[]string{"cert_template"},
nil,
),
RequestProcessingTime: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "request_processing_time_seconds"),
"Last time elapsed for certificate requests",
[]string{"cert_template"},
nil,
),
RetrievalsPerSecond: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "retrievals_total"),
"Total certificate retrieval requests processed",
[]string{"cert_template"},
nil,
),
RetrievalProcessingTime: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "retrievals_processing_time_seconds"),
"Last time elapsed for certificate retrieval request",
[]string{"cert_template"},
nil,
),
FailedRequestsPerSecond: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "failed_requests_total"),
"Total failed certificate requests processed",
[]string{"cert_template"},
nil,
),
IssuedRequestsPerSecond: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "issued_requests_total"),
"Total issued certificate requests processed",
[]string{"cert_template"},
nil,
),
PendingRequestsPerSecond: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "pending_requests_total"),
"Total pending certificate requests processed",
[]string{"cert_template"},
nil,
),
RequestCryptographicSigningTime: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "request_cryptographic_signing_time_seconds"),
"Last time elapsed for signing operation request",
[]string{"cert_template"},
nil,
),
RequestPolicyModuleProcessingTime: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "request_policy_module_processing_time_seconds"),
"Last time elapsed for policy module processing request",
[]string{"cert_template"},
nil,
),
ChallengeResponsesPerSecond: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "challenge_responses_total"),
"Total certificate challenge responses processed",
[]string{"cert_template"},
nil,
),
ChallengeResponseProcessingTime: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "challenge_response_processing_time_seconds"),
"Last time elapsed for challenge response",
[]string{"cert_template"},
nil,
),
SignedCertificateTimestampListsPerSecond: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "signed_certificate_timestamp_lists_total"),
"Total Signed Certificate Timestamp Lists processed",
[]string{"cert_template"},
nil,
),
SignedCertificateTimestampListProcessingTime: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "signed_certificate_timestamp_list_processing_time_seconds"),
"Last time elapsed for Signed Certificate Timestamp List",
[]string{"cert_template"},
nil,
),
}, nil
}

func (c *adcsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
if desc, err := c.collectADCSCounters(ctx, ch); err != nil {
log.Error("Failed collecting ADCS Metrics:", desc, err)
return err
}
return nil
}

type perflibADCS struct {
Name string
RequestsPerSecond float64 `perflib:"Requests/sec"`
RequestProcessingTime float64 `perflib:"Request processing time (ms)"`
RetrievalsPerSecond float64 `perflib:"Retrievals/sec"`
RetrievalProcessingTime float64 `perflib:"Retrieval processing time (ms)"`
FailedRequestsPerSecond float64 `perflib:"Failed Requests/sec"`
IssuedRequestsPerSecond float64 `perflib:"Issued Requests/sec"`
PendingRequestsPerSecond float64 `perflib:"Pending Requests/sec"`
RequestCryptographicSigningTime float64 `perflib:"Request cryptographic signing time (ms)"`
RequestPolicyModuleProcessingTime float64 `perflib:"Request policy module processing time (ms)"`
ChallengeResponsesPerSecond float64 `perflib:"Challenge Responses/sec"`
ChallengeResponseProcessingTime float64 `perflib:"Challenge Response processing time (ms)"`
SignedCertificateTimestampListsPerSecond float64 `perflib:"Signed Certificate Timestamp Lists/sec"`
SignedCertificateTimestampListProcessingTime float64 `perflib:"Signed Certificate Timestamp List processing time (ms)"`
}

func (c *adcsCollector) collectADCSCounters(ctx *ScrapeContext, ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
dst := make([]perflibADCS, 0)
if _, ok := ctx.perfObjects["Certification Authority"]; !ok {
return nil, errors.New("Perflib did not contain an entry for Certification Authority")
}
err := unmarshalObject(ctx.perfObjects["Certification Authority"], &dst)
if err != nil {
return nil, err
}
if len(dst) == 0 {
return nil, errors.New("Perflib query for Certification Authority (ADCS) returned empty result set")
}

for _, d := range dst {
n := strings.ToLower(d.Name)
if n == "" {
continue
}
ch <- prometheus.MustNewConstMetric(
c.RequestsPerSecond,
prometheus.CounterValue,
d.RequestsPerSecond,
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.RequestProcessingTime,
prometheus.GaugeValue,
milliSecToSec(d.RequestProcessingTime),
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.RetrievalsPerSecond,
prometheus.CounterValue,
d.RetrievalsPerSecond,
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.RetrievalProcessingTime,
prometheus.GaugeValue,
milliSecToSec(d.RetrievalProcessingTime),
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.FailedRequestsPerSecond,
prometheus.CounterValue,
d.FailedRequestsPerSecond,
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.IssuedRequestsPerSecond,
prometheus.CounterValue,
d.IssuedRequestsPerSecond,
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.PendingRequestsPerSecond,
prometheus.CounterValue,
d.PendingRequestsPerSecond,
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.RequestCryptographicSigningTime,
prometheus.GaugeValue,
milliSecToSec(d.RequestCryptographicSigningTime),
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.RequestPolicyModuleProcessingTime,
prometheus.GaugeValue,
milliSecToSec(d.RequestPolicyModuleProcessingTime),
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.ChallengeResponsesPerSecond,
prometheus.CounterValue,
d.ChallengeResponsesPerSecond,
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.ChallengeResponseProcessingTime,
prometheus.GaugeValue,
milliSecToSec(d.ChallengeResponseProcessingTime),
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.SignedCertificateTimestampListsPerSecond,
prometheus.CounterValue,
d.SignedCertificateTimestampListsPerSecond,
d.Name,
)
ch <- prometheus.MustNewConstMetric(
c.SignedCertificateTimestampListProcessingTime,
prometheus.GaugeValue,
milliSecToSec(d.SignedCertificateTimestampListProcessingTime),
d.Name,
)
}

return nil, nil
}
9 changes: 9 additions & 0 deletions collector/adcs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package collector

import (
"testing"
)

func BenchmarkADCSCollector(b *testing.B) {
benchmarkCollector(b, "adcs", adcsCollectorMethod)
}
4 changes: 4 additions & 0 deletions collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,7 @@ func expandEnabledChildCollectors(enabled string) []string {
sort.Strings(result)
return result
}

func milliSecToSec(t float64) float64 {
return t / 1000
}
4 changes: 0 additions & 4 deletions collector/remote_fx.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,3 @@ func (c *RemoteFxCollector) collectRemoteFXGraphicsCounters(ctx *ScrapeContext,

return nil, nil
}

func milliSecToSec(t float64) float64 {
return t / 1000
}
55 changes: 55 additions & 0 deletions docs/collector.adcs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# adcs collector

The adcs collector exposes metrics about Active Directory Certificate Services, Note that this collector has only been tested against Windows Server 2019.
Other Windows Server versions may work but are not tested.

|||
-|-
Metric name prefix | `adcs`
Data source | Perflib
Counters | `Certification Authority`
Enabled by default? | No

## Flags

None

## Metrics

Name | Description | Type | Labels
-----|-------------|------|-------
|requests_total|Total certificate requests processed|counter|`cert_template`|
|request_processing_time_seconds|Last time elapsed for certificate requests|gauge|`cert_template`|
|retrievals_total|Last time elapsed for certificate requests|counter|`cert_template`|
|retrievals_processing_time_seconds|Last time elapsed for certificate retrieval request|gauge|`cert_template`|
|failed_requests_total|Total failed certificate requests processed|counter|`cert_template`|
|issued_requests_total|Total issued certificate requests processed|counter|`cert_template`|
|pending_requests_total|Total pending certificate requests processed|counter|`cert_template`|
|request_cryptographic_signing_time_seconds|Last time elapsed for signing operation request|gauge|`cert_template`|
|request_policy_module_processing_time_seconds|Last time elapsed for policy module processing request|gauge|`cert_template`|
|challenge_responses_total|Total certificate challenge responses processed|counter|`cert_template`|
|challenge_response_processing_time_seconds|Last time elapsed for challenge response|gauge|`cert_template`|
|signed_certificate_timestamp_lists_total|Total Signed Certificate Timestamp Lists processed|counter|`cert_template`|
|signed_certificate_timestamp_list_processing_time_seconds|Last time elapsed for Signed Certificate Timestamp List|gauge|`cert_template`|

### Example metric
```
windows_adcs_issued_requests_total{cert_template="Administrator"} 0
windows_adcs_issued_requests_total{cert_template="DirectoryEmailReplication"} 0
windows_adcs_issued_requests_total{cert_template="DomainController"} 1
windows_adcs_issued_requests_total{cert_template="DomainControllerAuthentication"} 0
windows_adcs_issued_requests_total{cert_template="EFS"} 0
windows_adcs_issued_requests_total{cert_template="EFSRecovery"} 0
windows_adcs_issued_requests_total{cert_template="KerberosAuthentication"} 0
windows_adcs_issued_requests_total{cert_template="Machine"} 0
windows_adcs_issued_requests_total{cert_template="SubCA"} 0
windows_adcs_issued_requests_total{cert_template="User"} 0
windows_adcs_issued_requests_total{cert_template="WebServer"} 0
windows_adcs_issued_requests_total{cert_template="_Total"} 1
```

## Useful queries
_This collector does not yet have any useful queries added, we would appreciate your help adding them!_

## Alerting examples
_This collector does not yet have alerting examples, we would appreciate your help adding them!_

0 comments on commit 746158d

Please sign in to comment.