[OBJECT-16744] Add helpers for signing Nuget packages #57
6 changed files with 253 additions and 3 deletions
|
@ -1,5 +1,4 @@
|
|||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
@ -16,7 +15,7 @@ jobs:
|
|||
# `dotnet build` implies and replaces `dotnet pack` thanks to `GeneratePackageOnBuild`
|
||||
run: dotnet build
|
||||
|
||||
- name: Publish NuGet packages
|
||||
- name: Publish unsigned NuGet packages
|
||||
run: |-
|
||||
dotnet nuget add source \
|
||||
--name "$NUGET_REGISTRY" \
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -32,5 +32,8 @@ antlr-*.jar
|
|||
|
||||
# binary
|
||||
bin/
|
||||
release/
|
||||
obj/
|
||||
|
||||
# Repository signing keys
|
||||
release/maintainer.*
|
||||
release/ca.*
|
||||
|
|
58
Makefile
Normal file
58
Makefile
Normal file
|
@ -0,0 +1,58 @@
|
|||
DOTNET?=dotnet
|
||||
DOCKER?=docker
|
||||
|
||||
NUGET_REGISTRY?=TrueCloudLab
|
||||
NUGET_REGISTRY_URL?=https://git.frostfs.info/api/packages/TrueCloudLab/nuget/index.json
|
||||
NUGET_REGISTRY_USER?=
|
||||
NUGET_REGISTRY_PASSWORD?=
|
||||
|
||||
NUPKG=find -iname '*.nupkg' | grep . | xargs -d'\n' -t -r -n1
|
||||
RFC3161_TSA?=http://timestamp.digicert.com
|
||||
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
$(DOTNET) build
|
||||
|
||||
|
||||
.PHONY: sign
|
||||
sign: export NUGET_CERT_REVOCATION_MODE=offline
|
||||
sign: release/maintainer.pfx
|
||||
$(NUPKG) $(DOTNET) nuget sign --overwrite --certificate-path $< --timestamper "$(RFC3161_TSA)"
|
||||
@rm -v "$<" # maintainer.pfx is not password protected and must be ephemeral
|
||||
$(NUPKG) $(DOTNET) nuget verify
|
||||
|
||||
|
||||
.PHONY: publish
|
||||
publish:
|
||||
$(NUPKG) $(DOTNET) nuget verify
|
||||
$(NUPKG) $(DOTNET) nuget push --source "$(NUGET_REGISTRY)"
|
||||
|
||||
|
||||
.PHONY: nuget-registry
|
||||
nuget-registry:
|
||||
ifeq (,$(NUGET_REGISTRY_USER))
|
||||
$(error NUGET_REGISTRY_USER not set)
|
||||
endif
|
||||
ifeq (,$(NUGET_REGISTRY_PASSWORD))
|
||||
$(error NUGET_REGISTRY_PASSWORD not set)
|
||||
endif
|
||||
$(DOTNET) nuget add source \
|
||||
--name "$(NUGET_REGISTRY)" \
|
||||
--username "$(NUGET_REGISTRY_USER)" \
|
||||
--password "$(NUGET_REGISTRY_PASSWORD)" \
|
||||
--store-password-in-clear-text \
|
||||
"$(NUGET_REGISTRY_URL)"
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-$(NUPKG) rm -v
|
||||
|
||||
|
||||
.PHONY: container
|
||||
container:
|
||||
$(DOCKER) run --pull=always --rm -it -v "$$PWD:/src" -w /src git.frostfs.info/truecloudlab/env:dotnet-8.0
|
||||
|
||||
|
||||
include release/codesign.mk
|
82
release/README.md
Normal file
82
release/README.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
# Release process
|
||||
|
||||
## Preparing release
|
||||
|
||||
_TBD_
|
||||
|
||||
## Trusting TrueCloudLab code signing CA certificate
|
||||
|
||||
Verifying signatures (and signing) TrueCloudLab packages requires adding
|
||||
[TrueCloudLab Code Signing CA](ca.cert) to the list of trusted roots.
|
||||
|
||||
On Linux this can be done by appending [release/ca.cert](ca.cert) to one of:
|
||||
|
||||
- `/etc/pki/ca-trust/extracted/pem/objsign-ca-bundle.pem`: compatible with
|
||||
[update-ca-trust] and originally proposed in [.NET design docs]
|
||||
- `…/dotnet/sdk/X.Y.ZZZ/trustedroots/codesignctl.pem`: [fallback] codesigning certificate trust list for .NET
|
||||
|
||||
[update-ca-trust]: https://www.linux.org/docs/man8/update-ca-trust.html
|
||||
[.NET design docs]: https://github.com/dotnet/designs/blob/main/accepted/2021/signed-package-verification/re-enable-signed-package-verification-technical.md#linux
|
||||
[fallback]: https://github.com/dotnet/sdk/blob/11150c0ec9020625308edeec555a8b78dbfb2aa5/src/Layout/redist/trustedroots/README.md
|
||||
|
||||
## Signing Nuget packages
|
||||
|
||||
Repository maintainer places `maintainer.cert` and `maintainer.key` (see below
|
||||
regarding obtaining these files) into `release/` directory and then
|
||||
executes:
|
||||
|
||||
```console
|
||||
$ make build sign
|
||||
```
|
||||
|
||||
## Uploading packages to Nuget registry
|
||||
|
||||
**IMPORTANT: the following steps upload all `*.nupkg` files located under
|
||||
`src/`. Maintainer MUST make sure that no unnecessary package versions will be
|
||||
uploaded to the registry.**
|
||||
|
||||
Configure registry credentials (once per machine):
|
||||
|
||||
```console
|
||||
$ make nuget-registry NUGET_REGISTRY_USER=username NUGET_REGISTRY_PASSWORD=token
|
||||
```
|
||||
|
||||
Publish all locally built packages (implicitly clear existing `*.nupkg` and
|
||||
rebuild current version only):
|
||||
|
||||
```console
|
||||
$ make clean build sign publish
|
||||
```
|
||||
|
||||
|
||||
## Obtaining release signing certificate
|
||||
|
||||
Repository maintainer owns and keeps safe the release signing key
|
||||
(`maintainer.key`). Private key should never leave maintainer's machine and
|
||||
should be considered a highly sensitive secret.
|
||||
|
||||
- Generating new maintainer key and the corresponding CSR:
|
||||
|
||||
```console
|
||||
$ make maintainer.csr
|
||||
...lines skipped...
|
||||
Enter PEM pass phrase:
|
||||
Verifying - Enter PEM pass phrase:
|
||||
-----
|
||||
IMPORTANT: Keep maintainer.key private!
|
||||
|
||||
Certificate signing request is ready.
|
||||
Send maintainer.csr to CA administrator to obtain the certificate.
|
||||
```
|
||||
|
||||
Resulting CSR (`maintainer.csr`) does not contain any sensitive
|
||||
cryptographic material and may be passed to CA administrator through regular
|
||||
communication channels.
|
||||
|
||||
- CA administrator then issues the certificate (`make maintainer.cert`) and
|
||||
sends it back to the maintainer to be used in combination with
|
||||
`maintainer.key`
|
||||
|
||||
This procedure should be repeated once per machine per `maintainer.cert`
|
||||
lifetime (1 year) - typically just once per year since we expect the
|
||||
maintainer to use only a single computer to sign releases.
|
34
release/ca.cert
Normal file
34
release/ca.cert
Normal file
|
@ -0,0 +1,34 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIF2zCCA8OgAwIBAgIUa9xC/RgvFtUG/xeR016nn0B4K0YwDQYJKoZIhvcNAQEL
|
||||
BQAwdTELMAkGA1UEBhMCUlUxFTATBgNVBAoMDFRydWVDbG91ZExhYjEVMBMGA1UE
|
||||
CwwMVHJ1ZUNsb3VkTGFiMTgwNgYDVQQDDC9UcnVlQ2xvdWRMYWIgQ29kZSBTaWdu
|
||||
aW5nIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0yNTA0MTAxNTI2MTFaFw0zNTA0
|
||||
MDgxNTI2MTFaMHUxCzAJBgNVBAYTAlJVMRUwEwYDVQQKDAxUcnVlQ2xvdWRMYWIx
|
||||
FTATBgNVBAsMDFRydWVDbG91ZExhYjE4MDYGA1UEAwwvVHJ1ZUNsb3VkTGFiIENv
|
||||
ZGUgU2lnbmluZyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQCyANB4cjf+ZEAFx9RiUYXCAOPMV+jyqgcVbhzh2YKc
|
||||
9SlvGKRlc00Ar1RlFcrycdkIrTKmhhobiWsFp7UgphwLqRTCb5NB6qfUoWhnfiD9
|
||||
m0OBgeVX5wivVaibRI9PSTbFDcIhYUiNvwFJ6GduH/9zOxf1BvuL7LMaoyhIDcg/
|
||||
XVLuekE2lnX83zsedv0v/2jyyMY9Ct6N2BXzyHSAzSdYYg0F9Qu9fIMAPjoKhWPc
|
||||
PnotqaACjb1DScLUr3E/o2W1FfprTT2Pip/0AXxO4wixl4QWh9HeOKV22KRcCHo6
|
||||
3wNdg5q1ZVGTNBW0+yoB4jsSG8/JM+2Ujhc1ZnYH10armvGq/0Oc2YQE00960Wy8
|
||||
t0drCFWJUO1XHNeBxkkupmj7N1TAPbixtfiGZJhECOWOJwyMpcKixlt5P0cNH4N/
|
||||
p3vjyrGQxGLBIkgV/QgjfGkpTHKT1/H40YK6DliWJc01KfNTqn0K+/TIyF0n26kD
|
||||
BWYVlvDh5P1+V9DGuD2zeXB3PstoifD/Pd7D8wuqpm17noFE19MLp94xv03q9nEa
|
||||
jRMEd2J2buTLvMh5BBVH0Sm38QAHpSIZ9O3dSLvvjlALbVtwmcsNE9fgxiue3vTB
|
||||
iXNW8wWs+/DMYwbWyBoCwORxVOdOyc1JLn7qAAEUBweilPVXpWuzMLdUsifPiqrV
|
||||
dQIDAQABo2MwYTAdBgNVHQ4EFgQUEz4y/RvQMmbUFvf5JbGe/0PZR90wHwYDVR0j
|
||||
BBgwFoAUEz4y/RvQMmbUFvf5JbGe/0PZR90wDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||
HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADggIBAF79W9hMGnrKUWLDOcoeXDEn
|
||||
+gZxd5rjeF0tNEQGbWKGTJAGQdprOkzWQ47PewpFeS+ePpjOglBAt7cV2ZnOugAT
|
||||
Brx31vYpNAvYnUCYn+/IUqD8S/U4uErVS9zG9QjirZWo56eJP62vnScKuApCQCbA
|
||||
pp0zrIyJ+2lQKzlMOENRqzYYA/UTOqYTtnW6x2D8goVqCmDXpgpxEp5XliFjJSr6
|
||||
dOjiopNWMvaV3R/Bnd4i41taM7M6HpIV+gbXmEKEFS0ejVfzT8z1pTigN7GBqbxf
|
||||
nXD03eLUIsbMDv4ZQPrheN7nKnjRUn8kxz0SSK1m2YDrXW51m8fOs6aTvwC/cNe+
|
||||
FJMqQMF32i4IXVfUbyUJi+JMvawqm2wEY46vrh7siprY6rXsAzCKJo07i6jvUwnT
|
||||
TXMldSCPgTEqzT2JBzzr0tRfuPKsv0/NqflHvwfuMRCpcZ7jJZ700iN92xXkiQHP
|
||||
DmCZOILXcNclAth3nAnyY4XE5a8myv8bwYaPdJdIFlV+BoU/8mClDeA8ck4rDy12
|
||||
T5YChKew2oiL4j4B6v9/yrDjD1IT0gv4BWyPhb/n390BCEXt8g9auNcT0s6O8kEc
|
||||
VUDVc1519ocMCuWVuqUK9o2w0zu50/pBn4hVLfT3QyW8sqtlRKghOWtqZzigvCWF
|
||||
VjATeO5F/Z7OSDebHUGv
|
||||
-----END CERTIFICATE-----
|
74
release/codesign.mk
Normal file
74
release/codesign.mk
Normal file
|
@ -0,0 +1,74 @@
|
|||
PKI_ROLE?=maintainer
|
||||
PKI_DIR?=release
|
||||
|
||||
# Note: Only RSA signatures are supported (NU3013)
|
||||
# https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3013)
|
||||
|
||||
|
||||
ifeq ($(PKI_ROLE),maintainer)
|
||||
.PHONY: maintainer.csr
|
||||
maintainer.csr: $(PKI_DIR)/maintainer.csr
|
||||
$(PKI_DIR)/maintainer.csr: KEY=$(patsubst %.csr,%.key,$@)
|
||||
$(PKI_DIR)/maintainer.csr:
|
||||
openssl req \
|
||||
-new \
|
||||
-newkey rsa:4096 \
|
||||
-keyout $(KEY) \
|
||||
-out $@ \
|
||||
-sha256 \
|
||||
-addext keyUsage=critical,digitalSignature \
|
||||
-addext extendedKeyUsage=critical,codeSigning,msCodeCom \
|
||||
-subj "/C=RU/O=TrueCloudLab/OU=TrueCloudLab/CN=frostfs-sdk-csharp Release Team"
|
||||
@echo "IMPORTANT: Keep $(KEY) private!\n"
|
||||
@echo "Certificate signing request is ready.\nSend $@ to CA administrator to obtain the certificate."
|
||||
|
||||
$(PKI_DIR)/maintainer.pfx: $(PKI_DIR)/maintainer.cert $(PKI_DIR)/maintainer.key $(PKI_DIR)/ca.cert
|
||||
openssl verify \
|
||||
-CAfile $(PKI_DIR)/ca.cert \
|
||||
$(PKI_DIR)/maintainer.cert
|
||||
openssl pkcs12 \
|
||||
-export \
|
||||
-out $@ \
|
||||
-inkey $(PKI_DIR)/maintainer.key \
|
||||
-in $(PKI_DIR)/maintainer.cert \
|
||||
-CAfile $(PKI_DIR)/ca.cert \
|
||||
-chain \
|
||||
-passout pass:
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(PKI_ROLE),ca)
|
||||
.PHONY: maintainer.cert
|
||||
maintainer.cert: $(PKI_DIR)/maintainer.cert
|
||||
$(PKI_DIR)/maintainer.cert: CSR=$(patsubst %.cert,%.csr,$@)
|
||||
$(PKI_DIR)/maintainer.cert: $(PKI_DIR)/ca.key $(PKI_DIR)/ca.cert
|
||||
openssl req -noout -text -in $(CSR)
|
||||
@read -p "Review the CSR above. Press Enter to continue, Ctrl+C to cancel
" -r null
|
||||
openssl x509 \
|
||||
-req \
|
||||
-days 365 \
|
||||
-in $(CSR) \
|
||||
-copy_extensions copy \
|
||||
-ext keyUsage,extendedKeyUsage \
|
||||
-CA $(PKI_DIR)/ca.cert \
|
||||
-CAkey $(PKI_DIR)/ca.key \
|
||||
-CAcreateserial \
|
||||
-out $@
|
||||
echo >> $@
|
||||
cat $(PKI_DIR)/ca.cert >> $@
|
||||
openssl x509 -noout -text -in $@ -fingerprint -sha256
|
||||
@echo "Certificate is ready.\nSend $@ back to maintainer."
|
||||
|
||||
$(PKI_DIR)/ca.key: CERT=$(patsubst %.key,%.cert,$@)
|
||||
$(PKI_DIR)/ca.key:
|
||||
openssl req \
|
||||
-x509 \
|
||||
-newkey rsa:4096 \
|
||||
-keyout $@ \
|
||||
-out $(CERT) \
|
||||
-sha256 \
|
||||
-days 3650 \
|
||||
-addext keyUsage=critical,keyCertSign \
|
||||
-subj "/C=RU/O=TrueCloudLab/OU=TrueCloudLab/CN=TrueCloudLab Code Signing Certificate Authority"
|
||||
@echo "IMPORTANT: Keep $@ private!\n"
|
||||
endif
|
Loading…
Add table
Reference in a new issue