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

ca: log cert signing using JSON objects #7742

Merged
merged 9 commits into from
Nov 5, 2024
Merged

Conversation

jsha
Copy link
Contributor

@jsha jsha commented Oct 3, 2024

This makes the log events easier to parse, and makes it easier to consistently use the correct fields from the issuance request.

Also, reduce the number of fields that are logged on error events. Logging just the serial and the error in most cases should suffice to cross-reference the error with the item that we attempted to sign.

Some example log output from an integration test run, with the JSON manually prettified (using jq):

20:08:46.336020 6 boulder-ca 2Nun-Aw [AUDIT] Signing precert JSON={
  "CSR": "308202743082015c020100300030820122300d06092a864886f70d01010105000382010f003082010a0282010100c4e15ba41cc9f212f241d2dbdc072a902c92893a3da6205203483b68968f61bb9fb4dd169a6406e40a74c988d49d0883645684abc9e68a37b0b10bb99544b8518ed5a22ce036abf8ef242842df5866f1e405eaf2b3403387c06bffd516679f58cf7bd2ccb30155c095720a6ef5cfb49c424d6a6f2f58b166aedf708d56e21122530680d564cfa9aa53e1a8d139e11e2845af86b00dfb62e58a379a7042f376426e70492e135a0f75c4f838e00dac2d5253e484266d4c91541701f39897cab8c3b8d36ea766bfc90ef3095c93a1ffab640f78787e6580f7502346bf474fd036b0e1b789f730d560c5ddb7a212451456e7673eb48a7897d259925c37eda6ab1d2d0203010001a02f302d06092a864886f70d01090e3120301e301c0603551d1104153013821172616e642e63383565653933332e78797a300d06092a864886f70d01010b05000382010100244e3573dc9b8471a3e78833ec8a9295dd740dc12d81b9457f781cb690f580723782b69bfe106df019a0d35be30204682140771c6b7592e33dbf54ae023a830d37c6e56747b0eafecb3731dc6fc758aa2dbe9560431331cbc867178fba7372049a6e916b265e15c71ace3faa787821ca22c96c154827a8f0b31546466cb793140c73d61470ab9b89525839c14de0c0b41b8d5da99886284d57d4c948333b4726e065252b2707d6e40b618b5648a3171f5198d47c06a3e187e066a6b203533773b4f947fe31fab1b77f5604666faf2395ae128dfcc34bba6f383e48c68bdcbcae20c7f2096c405e0d67de3fee75b86dc023d09574a4fc1bfc157ecc84b04390a2",
  "IssuanceRequest": {
    "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxOFbpBzJ8hLyQdLb3AcqkCySiTo9piBSA0g7aJaPYbuftN0WmmQG5Ap0yYjUnQiDZFaEq8nmijewsQu5lUS4UY7VoizgNqv47yQoQt9YZvHkBerys0Azh8Br/9UWZ59Yz3vSzLMBVcCVcgpu9c+0nEJNam8vWLFmrt9wjVbiESJTBoDVZM+pqlPhqNE54R4oRa+GsA37YuWKN5pwQvN2Qm5wSS4TWg91xPg44A2sLVJT5IQmbUyRVBcB85iXyrjDuNNup2a/yQ7zCVyTof+rZA94eH5lgPdQI0a/R0/QNrDht4n3MNVgxd23ohJFFFbnZz60iniX0lmSXDftpqsdLQIDAQAB",
    "SubjectKeyId": "1ae2131c45563200d9f2d6c5f8bed9a3baf10c3e",
    "Serial": "7f6f6cfd5b8af2f7b85a7866885ba5944621",
    "NotBefore": "2024-10-25T19:10:16.314355666Z",
    "NotAfter": "2025-01-23T19:10:15.314355666Z",
    "CommonName": "rand.c85ee933.xyz",
    "DNSNames": [
      "rand.c85ee933.xyz"
    ],
    "IncludeMustStaple": false,
    "IncludeCTPoison": true
  },
  "Issuer": "int rsa a",
  "OrderID": 392,
  "Profile": "legacy",
  "ProfileHash": "0135c8cc516a218772a859cea4e3dd4860b88f309ea21d5264f7b774f9320e4e",
  "Requester": 493,
  "Result": {}
}
20:08:46.337624 6 boulder-ca sfCHcgA [AUDIT] Signing precert success JSON={
  "IssuanceRequest": {
    "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxOFbpBzJ8hLyQdLb3AcqkCySiTo9piBSA0g7aJaPYbuftN0WmmQG5Ap0yYjUnQiDZFaEq8nmijewsQu5lUS4UY7VoizgNqv47yQoQt9YZvHkBerys0Azh8Br/9UWZ59Yz3vSzLMBVcCVcgpu9c+0nEJNam8vWLFmrt9wjVbiESJTBoDVZM+pqlPhqNE54R4oRa+GsA37YuWKN5pwQvN2Qm5wSS4TWg91xPg44A2sLVJT5IQmbUyRVBcB85iXyrjDuNNup2a/yQ7zCVyTof+rZA94eH5lgPdQI0a/R0/QNrDht4n3MNVgxd23ohJFFFbnZz60iniX0lmSXDftpqsdLQIDAQAB",
    "SubjectKeyId": "1ae2131c45563200d9f2d6c5f8bed9a3baf10c3e",
    "Serial": "7f6f6cfd5b8af2f7b85a7866885ba5944621",
    "NotBefore": "2024-10-25T19:10:16.314355666Z",
    "NotAfter": "2025-01-23T19:10:15.314355666Z",
    "CommonName": "rand.c85ee933.xyz",
    "DNSNames": [
      "rand.c85ee933.xyz"
    ],
    "IncludeMustStaple": false,
    "IncludeCTPoison": true
  },
  "Issuer": "int rsa a",
  "OrderID": 392,
  "Profile": "legacy",
  "ProfileHash": "0135c8cc516a218772a859cea4e3dd4860b88f309ea21d5264f7b774f9320e4e",
  "Requester": 493,
  "Result": {
    "Precertificate": "30820413308202fba00302010202127f6f6cfd5b8af2f7b85a7866885ba5944621300d06092a864886f70d01010b05003035310b300906035504061302555331123010060355040a1309676f6f6420677579733112301006035504031309696e74207273612061301e170d3234313032353139313031365a170d3235303132333139313031355a301c311a30180603550403131172616e642e63383565653933332e78797a30820122300d06092a864886f70d01010105000382010f003082010a0282010100c4e15ba41cc9f212f241d2dbdc072a902c92893a3da6205203483b68968f61bb9fb4dd169a6406e40a74c988d49d0883645684abc9e68a37b0b10bb99544b8518ed5a22ce036abf8ef242842df5866f1e405eaf2b3403387c06bffd516679f58cf7bd2ccb30155c095720a6ef5cfb49c424d6a6f2f58b166aedf708d56e21122530680d564cfa9aa53e1a8d139e11e2845af86b00dfb62e58a379a7042f376426e70492e135a0f75c4f838e00dac2d5253e484266d4c91541701f39897cab8c3b8d36ea766bfc90ef3095c93a1ffab640f78787e6580f7502346bf474fd036b0e1b789f730d560c5ddb7a212451456e7673eb48a7897d259925c37eda6ab1d2d0203010001a382013430820130300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000301d0603551d0e041604141ae2131c45563200d9f2d6c5f8bed9a3baf10c3e301f0603551d23041830168014cea38e8a1f859ca88775aea33ba6e43d5dcace2a306906082b06010505070101045d305b302706082b06010505073001861b687474703a2f2f63612e6578616d706c652e6f72673a343030322f303006082b060105050730028624687474703a2f2f63612e6578616d706c652e6f72673a343530322f696e742d7273612d61301c0603551d1104153013821172616e642e63383565653933332e78797a30130603551d20040c300a3008060667810c0102013013060a2b06010401d6790204030101ff04020500300d06092a864886f70d01010b05000382010100464587db0b67454403fad22f142e05afdc2ef542d1361d09d6fc27753b7f62959e37dfe89e5cf5d36e19f60e4fae29657ae009acedb003ca2159798744c70d5c6375bd37674a6ef4bbc631ef74c3fd57962ede1cab06c36ab21485fc9b6508bf255c67b506ecee7d503ab28bf0fdb0b1a23670a4a02660a56eca1989a080bfd74fc1e4f8c6447174bcae3517f366fba12fd988c9c6ca7b810602f63e5638825171043bb1b78fd5d8411a87f78373af51a1b23b83538335e8963cf0a244c763cfcd4a9fbad0444cd9439adb69ae7f61fcfdf0f523787029803a48a0d4488f0e3ddd103c1a95fc5a241e9b3c06fd7fe1d856b95bef450721b4fbac991d98b4c9c8"
  }
}
20:08:46.355807 6 boulder-ca 64v96QU [AUDIT] Signing cert JSON={
  "IssuanceRequest": {
    "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxOFbpBzJ8hLyQdLb3AcqkCySiTo9piBSA0g7aJaPYbuftN0WmmQG5Ap0yYjUnQiDZFaEq8nmijewsQu5lUS4UY7VoizgNqv47yQoQt9YZvHkBerys0Azh8Br/9UWZ59Yz3vSzLMBVcCVcgpu9c+0nEJNam8vWLFmrt9wjVbiESJTBoDVZM+pqlPhqNE54R4oRa+GsA37YuWKN5pwQvN2Qm5wSS4TWg91xPg44A2sLVJT5IQmbUyRVBcB85iXyrjDuNNup2a/yQ7zCVyTof+rZA94eH5lgPdQI0a/R0/QNrDht4n3MNVgxd23ohJFFFbnZz60iniX0lmSXDftpqsdLQIDAQAB",
    "SubjectKeyId": "1ae2131c45563200d9f2d6c5f8bed9a3baf10c3e",
    "Serial": "7f6f6cfd5b8af2f7b85a7866885ba5944621",
    "NotBefore": "2024-10-25T19:10:16Z",
    "NotAfter": "2025-01-23T19:10:15Z",
    "CommonName": "rand.c85ee933.xyz",
    "DNSNames": [
      "rand.c85ee933.xyz"
    ],
    "IncludeMustStaple": false,
    "IncludeCTPoison": false
  },
  "Issuer": "int rsa a",
  "OrderID": 392,
  "Profile": "legacy",
  "ProfileHash": "0135c8cc516a218772a859cea4e3dd4860b88f309ea21d5264f7b774f9320e4e",
  "Requester": 493,
  "Result": {}
}
20:08:46.357517 6 boulder-ca rrKiwws [AUDIT] Signing cert success JSON={
  "IssuanceRequest": {
    "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxOFbpBzJ8hLyQdLb3AcqkCySiTo9piBSA0g7aJaPYbuftN0WmmQG5Ap0yYjUnQiDZFaEq8nmijewsQu5lUS4UY7VoizgNqv47yQoQt9YZvHkBerys0Azh8Br/9UWZ59Yz3vSzLMBVcCVcgpu9c+0nEJNam8vWLFmrt9wjVbiESJTBoDVZM+pqlPhqNE54R4oRa+GsA37YuWKN5pwQvN2Qm5wSS4TWg91xPg44A2sLVJT5IQmbUyRVBcB85iXyrjDuNNup2a/yQ7zCVyTof+rZA94eH5lgPdQI0a/R0/QNrDht4n3MNVgxd23ohJFFFbnZz60iniX0lmSXDftpqsdLQIDAQAB",
    "SubjectKeyId": "1ae2131c45563200d9f2d6c5f8bed9a3baf10c3e",
    "Serial": "7f6f6cfd5b8af2f7b85a7866885ba5944621",
    "NotBefore": "2024-10-25T19:10:16Z",
    "NotAfter": "2025-01-23T19:10:15Z",
    "CommonName": "rand.c85ee933.xyz",
    "DNSNames": [
      "rand.c85ee933.xyz"
    ],
    "IncludeMustStaple": false,
    "IncludeCTPoison": false
  },
  "Issuer": "int rsa a",
  "OrderID": 392,
  "Profile": "legacy",
  "ProfileHash": "0135c8cc516a218772a859cea4e3dd4860b88f309ea21d5264f7b774f9320e4e",
  "Requester": 493,
  "Result": {
    "Certificate": "30820505308203eda00302010202127f6f6cfd5b8af2f7b85a7866885ba5944621300d06092a864886f70d01010b05003035310b300906035504061302555331123010060355040a1309676f6f6420677579733112301006035504031309696e74207273612061301e170d3234313032353139313031365a170d3235303132333139313031355a301c311a30180603550403131172616e642e63383565653933332e78797a30820122300d06092a864886f70d01010105000382010f003082010a0282010100c4e15ba41cc9f212f241d2dbdc072a902c92893a3da6205203483b68968f61bb9fb4dd169a6406e40a74c988d49d0883645684abc9e68a37b0b10bb99544b8518ed5a22ce036abf8ef242842df5866f1e405eaf2b3403387c06bffd516679f58cf7bd2ccb30155c095720a6ef5cfb49c424d6a6f2f58b166aedf708d56e21122530680d564cfa9aa53e1a8d139e11e2845af86b00dfb62e58a379a7042f376426e70492e135a0f75c4f838e00dac2d5253e484266d4c91541701f39897cab8c3b8d36ea766bfc90ef3095c93a1ffab640f78787e6580f7502346bf474fd036b0e1b789f730d560c5ddb7a212451456e7673eb48a7897d259925c37eda6ab1d2d0203010001a382022630820222300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000301d0603551d0e041604141ae2131c45563200d9f2d6c5f8bed9a3baf10c3e301f0603551d23041830168014cea38e8a1f859ca88775aea33ba6e43d5dcace2a306906082b06010505070101045d305b302706082b06010505073001861b687474703a2f2f63612e6578616d706c652e6f72673a343030322f303006082b060105050730028624687474703a2f2f63612e6578616d706c652e6f72673a343530322f696e742d7273612d61301c0603551d1104153013821172616e642e63383565653933332e78797a30130603551d20040c300a3008060667810c01020130820103060a2b06010401d6790204020481f40481f100ef0076007bdd204f27382a46691efda981e48e4b6db831debfdb5526588c5117d997bde200000192c54bb6040000040300473045022100dec9dfd11aff884add97feba4c216566a6eb6c16275cc452c860d03d2e63c7f402203f02429174a50c36cea84e64a976c2fd2785790578abdc36d22cb6877fc248570075003aa93f4efd1c5129c42786d96b47a9ae6dc8410e1780d72fdb4fdb5e2c65c67400000192c54bb6040000040300463044022073ed8841fffb327b3adbf56be470363abbeff5b116d1d1b6dca35217f397e6d002206221476321178f7850797f76b6fb92859bb4e7ae9c7306079c935e7f7e1093c2300d06092a864886f70d01010b050003820101002733d13d9b4f83c176ed949bef6e18313e990b7c59f8726a2523178429825f17cf9a12a836e491bd1cc3de651d322e2eda45b7e85c8e9e1b23923af244b6c93cf44e5859ec30254466d5d8ab8b3cb7ef5884773a48a828682da854ee804e3cb4253a3a685062080dc59847110a3a13aae1b8188f0232309b8c7fc6bcbb12fa21a238b743ba3cae4a5952e844cc9737499e17e753a0ca91f0c43d03ca869d379bc045bfd16684248ecad2161d3319b689b28af4e9dfa776a3dddc179d397a1f2b9899adc4f686d59c6d8bb2ffae63f23a95b3a58a951a77933884f3876853dbec38c655489ad75d6ace3d29791c053a0ab308f0d8af8352cb5e30de3b49f31d3b"
  }
}

One downside is that this increases the total log size (10kB above, vs 7kB from a similar production issuance) due in part to more repetition. For example, both the "signing cert" and "signing cert success" log lines include the full precert DER.

Note that our long-term plan for more structured logs is to have a unique event id to join logs on, which can avoid this repetition. But since we don't currently have convenient ways to do that join, some duplication (as we currently have in the logs) seems reasonable.

jsha added 2 commits October 2, 2024 16:16
Previously, we logged csr.DNSNames along with the precertificate issuance
events, but this was potentially misleading. For instance, if a CSR contained
only a CN and no SANs, this set would be empty.

Instead, log the uniquified, lowercased, sorted SANs that are actually issued.

Also, emit precert=[] in issuePrecertificateInner, which is consistent with the
field name used when the final certificate is issued.
This makes the log events easier to parse, and makes it easier to consistently
use the correct fields from the issuance request.

Also, reduce the number of fields that are logged on error events. Logging just
the serial and the error in most cases should suffice to cross-reference the
error with the item that we attempted to sign.
Copy link
Contributor

@aarongable aarongable left a comment

Choose a reason for hiding this comment

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

Generally I like this approach. I'm a much bigger fan of logging a single consistent json object than our custom =[...] format. I have a few tiny questions/concerns about this precise approach, but nothing that would stop me from saying LGTM on this change essentially as-is.

  • Is the change to the ca.json log levels intentional? Or is that just from your own debugging?
  • I'd like to chat about the pros/cons of using logEvent := map[string]any{...} versus using var logEvent struct{...}{...} or even defining a type logEvent struct {...} higher up in the file. Using a map certainly feels closer to the raw json that it will eventually produce, but also leads to IMO-unidiomatic code like delete(logEvent, "csr") and the hand-written IssuanceRequest.MarshalJSON() method which has no mechanism to guarantee that a newly-added struct field gets reflected in the final output json.

Base automatically changed from ca-logging-consistent to main October 4, 2024 20:56
@jsha
Copy link
Contributor Author

jsha commented Oct 7, 2024

Is the change to the ca.json log levels intentional? Or is that just from your own debugging?

Just for personal testing / if anyone else wanted to try this branch locally.

I'd like to chat about the pros/cons of using logEvent := map[string]any{...} versus using var logEvent struct{...}{...} or even defining a type logEvent struct {...} higher up in the file.

I think the logEvent struct approach is probably better.

Using a map certainly feels closer to the raw json that it will eventually produce, but also leads to IMO-unidiomatic code like delete(logEvent, "csr")

FWIW, this is the idiomatic (and only) way to delete an element from a map. And I don't think deleting elements from maps is un-idiomatic. In the struct case, it would be something like json:omitempty, combined with logEvent.csr = "". More or less a wash IMO.

and the hand-written IssuanceRequest.MarshalJSON() method which has no mechanism to guarantee that a newly-added struct field gets reflected in the final output json.

This one is a little trickier. Probably what we need here is to define a newtype that wraps some of the fields - like type jsonPublicKey crypto.PublicKey and then write custom MarshalJSON implementations for those.

@aarongable
Copy link
Contributor

FWIW, this is the idiomatic (and only) way to delete an element from a map. And I don't think deleting elements from maps is un-idiomatic.

I think that deleting elements with a hard-coded key (as opposed to, say, a key that you got from a range loop) is somewhat non-idiomatic, because it means you're hard-coding that key in multiple different places and those have to stay in sync. Using a struct fixes this because the compiler will tell you if the field name gets out of sync.

define a newtype

image

ca/ca.go Outdated Show resolved Hide resolved
ca/ca.go Outdated Show resolved Hide resolved
@jsha jsha marked this pull request as ready for review October 25, 2024 20:14
@jsha jsha requested a review from a team as a code owner October 25, 2024 20:14
@jsha jsha requested a review from beautifulentropy October 25, 2024 20:14
@jsha
Copy link
Contributor Author

jsha commented Oct 25, 2024

I've updated the top comment to show the most recent iteration of the JSON output.

@aarongable aarongable merged commit cb56bf6 into main Nov 5, 2024
12 checks passed
@aarongable aarongable deleted the log-object-precert branch November 5, 2024 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants