Skip to content

Commit

Permalink
monitor: add ability to ignore expiration of signer ids
Browse files Browse the repository at this point in the history
This patch adds an env var of comma-separated signer ids to the monitor.
The signer ids in the env var will have any expiration date violations
ignored. In the monitor, the expiration violations include the
expiration being close to the current date.

I went back and forth on using an env var or a command-line flag. I
could go either way.
  • Loading branch information
jmhodges committed Dec 12, 2024
1 parent 9194570 commit 052aaea
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 11 deletions.
6 changes: 4 additions & 2 deletions tools/autograph-monitor/contentsignaturepki.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"net/http"
"slices"
"time"

"github.com/mozilla-services/autograph/formats"
Expand Down Expand Up @@ -55,7 +56,7 @@ const month = 4 * week
// expirations.
//
// Chains with leaf/EE CommonNames in ignoredCerts are ignored.
func verifyContentSignature(x5uClient *http.Client, notifier Notifier, rootHashes []string, ignoredCerts map[string]bool, response formats.SignatureResponse, input []byte) (err error) {
func verifyContentSignature(x5uClient *http.Client, notifier Notifier, rootHashes []string, ignoredCerts map[string]bool, ignoreExpiredSignerIds []string, response formats.SignatureResponse, input []byte) (err error) {
if response.X5U == "" {
return fmt.Errorf("content signature response is missing an X5U to fetch")
}
Expand Down Expand Up @@ -98,7 +99,8 @@ func verifyContentSignature(x5uClient *http.Client, notifier Notifier, rootHashe
err = certChainPendingExpiration(certs)
if err != nil {
// check if we should ignore this cert
if _, ok := ignoredCerts[certs[0].Subject.CommonName]; ok {
ignoreByCN := ignoredCerts[certs[0].Subject.CommonName]
if ignoreByCN || slices.Contains(ignoreExpiredSignerIds, response.SignerID) {
log.Printf("ignoring chain EE CN %q pending expiration error: %q", certs[0].Subject.CommonName, err)
return nil
}
Expand Down
33 changes: 26 additions & 7 deletions tools/autograph-monitor/contentsignaturepki_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,13 @@ func Test_verifyContentSignature(t *testing.T) {
var typedNilNotifier Notifier

type args struct {
x5uClient *http.Client
notifier Notifier
rootHashes []string
ignoredCerts map[string]bool
response formats.SignatureResponse
input []byte
x5uClient *http.Client
notifier Notifier
rootHashes []string
ignoredExpirationSignerIds []string
ignoredCerts map[string]bool
response formats.SignatureResponse
input []byte
}
tests := []struct {
name string
Expand Down Expand Up @@ -477,6 +478,24 @@ func Test_verifyContentSignature(t *testing.T) {
wantErr: true,
errSubStr: `root certificate 2 "autograph unit test self-signed root" expires in less than 15 months`,
},
{name: "expiring root's expiration is ignored",
args: args{
x5uClient: &http.Client{},
notifier: nil,
rootHashes: []string{sha2Fingerprint(testRoot16DaysToExpiration)},
ignoredExpirationSignerIds: []string{"normankey"},
response: formats.SignatureResponse{
Type: "contentsignature",
Mode: "p384ecdsa",
SignerID: "normankey",
Signature: "qGjS1QmB2xANizjJqrGmIPoojzjBrTV5kgi01p1ELnfKwH4E3UDTZRf-9K7PCEwjt0mOzd1bBmRBKcnWZNFAMvAduBwfAPHFGpX-YKBoRSLHuA6QuiosEydnZEs5ykAR",
X5U: testRootExpiringSoonChainTestServer.URL,
},
input: signerTestData,
},
wantErr: false,
errSubStr: "",
},
}
for _, tt := range tests {
notifier := tt.args.notifier
Expand All @@ -489,7 +508,7 @@ func Test_verifyContentSignature(t *testing.T) {
}

t.Run(tt.name, func(t *testing.T) {
err := verifyContentSignature(tt.args.x5uClient, notifier, tt.args.rootHashes, tt.args.ignoredCerts, tt.args.response, tt.args.input)
err := verifyContentSignature(tt.args.x5uClient, notifier, tt.args.rootHashes, tt.args.ignoredCerts, tt.args.ignoredExpirationSignerIds, tt.args.response, tt.args.input)

if (err != nil) != tt.wantErr {
t.Errorf("verifyContentSignature() error = %v, wantErr %v", err, tt.wantErr)
Expand Down
20 changes: 18 additions & 2 deletions tools/autograph-monitor/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"encoding/pem"
"errors"
"flag"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -40,13 +41,18 @@ type configuration struct {
depRootHashes []string
depTruststore *x509.CertPool

// signer IDs to ignore expiration warnings for
ignoreExpiredSignerIds []string

// notifier raises and resolves warnings
notifier Notifier
}

const inputdata string = "AUTOGRAPH MONITORING"

func main() {
flag.Parse()

autographURLEnvVar := strings.TrimSpace(os.Getenv("AUTOGRAPH_URL"))
if autographURLEnvVar == "" {
log.Fatal("AUTOGRAPH_URL must be set to the base url of the autograph service")
Expand All @@ -65,6 +71,16 @@ func main() {
log.Fatal("AUTOGRAPH_KEY must be set to the api monitoring key")
}

ignoredExpSignerIdsVar := os.Getenv("IGNORE_EXPIRATION_SIGNER_IDS")
var ignoreExpiredSignerIds []string
if ignoredExpSignerIdsVar != "" {
ignoreExpiredSignerIds = strings.Split(ignoredExpSignerIdsVar, ",")
for i, id := range ignoreExpiredSignerIds {
ignoreExpiredSignerIds[i] = strings.TrimSpace(id)
}
}
conf.ignoreExpiredSignerIds = ignoreExpiredSignerIds

// configure monitor to check responses against Fx stage or
// prod or autograph dev code signing PKI roots and CA root
// certs defined in constants.go
Expand Down Expand Up @@ -210,11 +226,11 @@ func monitor(conf *configuration, client *http.Client) error {
// The X5U is optional for contentsignature signers.
err = contentsignature.VerifyResponse([]byte(inputdata), response)
} else {
err = verifyContentSignature(x5uClient, conf.notifier, conf.rootHashes, contentSignatureIgnoredLeafCertCNs, response, []byte(inputdata))
err = verifyContentSignature(x5uClient, conf.notifier, conf.rootHashes, contentSignatureIgnoredLeafCertCNs, conf.ignoreExpiredSignerIds, response, []byte(inputdata))
}
case contentsignaturepki.Type:
log.Printf("Verifying content signature pki from signer %q", response.SignerID)
err = verifyContentSignature(x5uClient, conf.notifier, conf.rootHashes, contentSignatureIgnoredLeafCertCNs, response, []byte(inputdata))
err = verifyContentSignature(x5uClient, conf.notifier, conf.rootHashes, contentSignatureIgnoredLeafCertCNs, conf.ignoreExpiredSignerIds, response, []byte(inputdata))
case xpi.Type:
log.Printf("Verifying XPI signature from signer %q", response.SignerID)
err = verifyXPISignature(response.Signature, conf.truststore, conf.depTruststore)
Expand Down

0 comments on commit 052aaea

Please sign in to comment.