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

doc: update README #84

Merged
merged 33 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e3e3fee
feat: refactor describe-key command & add unit test
JeyJeyGao Mar 8, 2023
daa60eb
feat: add installation script and update README
JeyJeyGao Mar 9, 2023
d278fc8
fix: update code
JeyJeyGao Mar 9, 2023
b5e05d6
fix: update code
JeyJeyGao Mar 9, 2023
a69d26c
fix: update code
JeyJeyGao Mar 9, 2023
fc87bb5
fix: update code
JeyJeyGao Mar 9, 2023
d4fc080
fix: update code
JeyJeyGao Mar 9, 2023
ebfd654
fix: update code
JeyJeyGao Mar 9, 2023
b450522
fix: golint
JeyJeyGao Mar 9, 2023
c1b0750
fix: update code
JeyJeyGao Mar 9, 2023
9dd776f
fix: update code
JeyJeyGao Mar 9, 2023
d52bbf1
fix: update code
JeyJeyGao Mar 10, 2023
979d2df
fix: download with curl instead of wget
JeyJeyGao Mar 10, 2023
1fc930b
fix: update code
JeyJeyGao Mar 10, 2023
aab25eb
fix: update codecov target to 60% to pass the check
JeyJeyGao Mar 10, 2023
cd13669
fix: update doc
JeyJeyGao Mar 10, 2023
cfff6be
fix: update doc
JeyJeyGao Mar 13, 2023
3345b07
Merge remote-tracking branch 'upstream/main' into feat/update_doc
JeyJeyGao Mar 13, 2023
d899c23
fix: update codecov
JeyJeyGao Mar 13, 2023
9100207
fix: update doc
JeyJeyGao Mar 13, 2023
bdbf450
doc: update
JeyJeyGao Mar 14, 2023
2db644e
doc: update
JeyJeyGao Mar 14, 2023
8da1f15
doc: update
JeyJeyGao Mar 14, 2023
85cf03d
doc: update doc
JeyJeyGao Mar 14, 2023
9c0fbdf
doc: update doc
JeyJeyGao Mar 15, 2023
14f95a2
doc: update
JeyJeyGao Mar 15, 2023
6988dd0
doc: update
JeyJeyGao Mar 29, 2023
6f28c15
doc: update
JeyJeyGao Mar 29, 2023
6e0a3bc
doc: update
JeyJeyGao Mar 29, 2023
c1848e9
doc: update
JeyJeyGao Mar 29, 2023
99cfa4c
doc: update
JeyJeyGao Mar 29, 2023
7af57b7
fix: golint
JeyJeyGao Mar 29, 2023
46a2f6c
doc: update
JeyJeyGao Mar 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 42 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,58 @@

[![codecov](https://codecov.io/gh/Azure/notation-azure-kv/branch/main/graph/badge.svg)](https://codecov.io/gh/Azure/notation-azure-kv)

Azure Provider for the Notary v2 [Notation CLI](https://github.com/notaryproject/notation)
Azure Provider for the [Notation CLI](https://github.com/notaryproject/notation)

## Getting Started:
The following summarizes the steps to configure the Azure Key Vault notation plugin, configure gatekeeper, sign and verify a container image to Azure Kubernetes Service
The `notation-azure-kv` plugin allows you to sign the Notation-generated payload with a certificate in Azure Key Vault (AKV). The certificate and private key are stored in AKV and the plugin will request signing and obtain the leaf certificate from AKV.

```bash
# Sign in with Azure CLI.
# Other authorization methods are also available.
# See https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authorizatio
az login
The plugin supports authentication by [Azure CLI](https://learn.microsoft.com/cli/azure/authenticate-azure-cli) or [Managed Identity](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview). Azure CLI authenticate is used by default. To enable `Managed Identity` authentication, set the `AKV_AUTH_METHOD` environment variable to `AKV_AUTH_FROM_MI`.

# Add signing and verification keys to the notation configuration policy
notation key add --name $KEY_NAME --plugin azure-kv --id $KEY_ID
notation cert add --name $KEY_NAME $CERT_PATH
## Installation the AKV plugin
Before you begin, make sure the latest version of the [Notation CLI has been installed](https://notaryproject.dev/docs/installation/cli/).

# Install ratify, with the verification key
helm install ratify ratify/charts/ratify \
--set registryCredsSecret=regcred \
--set ratifyTestCert=$PUBLIC_KEY
kubectl apply -f ./ratify/charts/ratify-gatekeeper/templates/constraint.yaml
1. Navigate to the [Releases](https://github.com/Azure/notation-azure-kv/releases) page and select the latest release of `notation-azure-kv`. Under the *Assets* section, select the `notation-azure-kv` binary for your platform.
2. Validate the checksum using the values in `checksums.txt` and then install the plugin.

# Remotely sign with Azure Key Vault
notation sign --key $KEY_NAME $IMAGE
For Linux Bash:
```sh
version=0.6.0

# Deploy the image, with Gatekeeper, Ratify and Notary v2 validation of the signed image
kubectl run net-monitor --image=$IMAGE -n demo
```
# validate checksum
cat checksums.txt | grep notation-azure-kv_${version}_linux_amd64.tar.gz | sha256sum -c

See [documentation for details on remote signing with Azure Key Vault, validating a deployment to AKS with Notation and Ratify, using a simple setup script.](docs/nv2-bicep.md).
# install the plugin
mkdir -p "$HOME/.config/notation/plugins/azure-kv"
tar zxf notation-azure-kv_${version}_linux_amd64.tar.gz -C "$HOME/.config/notation/plugins/azure-kv" notation-azure-kv
```
For macOS Zsh:
```sh
version=0.6.0

# validate checksum
cat checksums.txt | grep notation-azure-kv_${version}_darwin_amd64.tar.gz | shasum -a 256 -c

# install the plugin
mkdir -p "$HOME/Library/Application Support/notation/plugins/azure-kv"
tar zxf notation-azure-kv_${version}_darwin_amd64.tar.gz -C "$HOME/Library/Application Support/notation/plugins/azure-kv" notation-azure-kv
```
For Windows Powershell:
```powershell
$version = "0.6.0"

# validate checksum
(Get-FileHash .\notation-azure-kv_${version}_windows_amd64.zip).Hash

# install the plugin
mkdir "$env:AppData\notation\plugins\azure-kv"
Expand-Archive -Path notation-azure-kv_${version}_windows_amd64.zip -DestinationPath "$env:AppData\notation\plugins\azure-kv"
```
3. Run `notation plugin list` and confirm the `azure-kv` plugin is installed.

## Getting started
1. [Sign and verify an artifact with a self-signed Azure Key Vault certificate](docs/self-signed-workflow.md)
2. [Sign and verify an artifact with a certificate signed by a trusted CA in Azure Key Vault](docs/ca-signed-workflow.md)

> **Note** Please make sure the certificate is in PEM format. PCKS#12 will be supported in the future.
## Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Expand Down
6 changes: 3 additions & 3 deletions cmd/notation-azure-kv/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ type certificateMock struct {
err error
}

func (c *certificateMock) Sign(ctx context.Context, algorithm azkeys.JSONWebKeySignatureAlgorithm, digest []byte) ([]byte, error) {
func (c *certificateMock) Sign(_ context.Context, _ azkeys.JSONWebKeySignatureAlgorithm, _ []byte) ([]byte, error) {
panic("not implemented") // TODO: Implement
}

func (c *certificateMock) CertificateChain(ctx context.Context) ([]*x509.Certificate, error) {
func (c *certificateMock) CertificateChain(_ context.Context) ([]*x509.Certificate, error) {
panic("not implemented") // TODO: Implement
}

func (c *certificateMock) Certificate(ctx context.Context) (*x509.Certificate, error) {
func (c *certificateMock) Certificate(_ context.Context) (*x509.Certificate, error) {
return c.cert, c.err
}

Expand Down
133 changes: 133 additions & 0 deletions docs/ca-signed-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Sign and verify an artifact with a certificate signed by a trusted CA in Azure Key Vault
> **Note** The following guide can be executed on Linux bash, macOS Zsh and Windows WSL
1. [Install the Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli)
2. Log in to Azure with Azure CLI, set the subscription and make sure the `GetCertificate` and `Sign` permission have been granted to your role:
```sh
az login
az account set --subscription $subscriptionID
```
3. Create an Azure Key Vault:
```sh
resourceGroup=<your-resource-group-name>
keyVault=<your-key-vault-name>
location=westus
certName=notationLeafCert

# create a resource group
az group create -n $resourceGroup -l $location

# create a Azure Key Vault
az keyvault create -l $location -n $keyVault --resource-group $resourceGroup
```
4. Create a Certificate Signing Request (CSR):
```sh
# generate certificate policy
cat <<EOF > ./leafCert.json
{
"issuerParameters": {
"certificateTransparency": null,
"name": "Unknown"
},
"keyProperties": {
"curve": null,
"exportable": false,
"keySize": 2048,
"keyType": "RSA",
"reuseKey": true
},
"secretProperties": {
"contentType": "application/x-pem-file"
},
"x509CertificateProperties": {
"ekus": [
"1.3.6.1.5.5.7.3.3"
],
"keyUsage": [
"digitalSignature"
],
"subject": "CN=Test-Signer,C=US,ST=WA,O=notation",
"validityInMonths": 12
}
}
EOF

# create the leaf certificate
az keyvault certificate create -n $certName --vault-name $keyVault -p @leafCert.json

# get the CSR
CSR=$(az keyvault certificate pending show --vault-name $keyVault --name $certName --query 'csr' -o tsv)
CSR_PATH=${certName}.csr
printf -- "-----BEGIN CERTIFICATE REQUEST-----\n%s\n-----END CERTIFICATE REQUEST-----\n" $CSR > ${CSR_PATH}
```
5. Please take `${certName}.csr` file to a trusted CA to sign and issue your certificate, or you can use `openssl` tool to sign it locally for testing.
6. After you get the leaf certificate, you can merge the leaf certificate (`$leafCert`) to your Azure Key Vault:
```sh
az keyvault certificate pending merge --vault-name $keyVault --name $certName --file $leafCert

# get the key identifier
keyID=$(az keyvault certificate show -n $certName --vault-name $keyVault --query 'kid' -o tsv)
```
7. [Create an Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-get-started-portal?tabs=azure-cli). The remaining steps use the example login server `<registry-name>.azurecr.io`, but you must substitute your own login server value.
8. Log in to container registry and push an image for signing:
```sh
registryName="<registry-name>"
server="${registryName}.azurecr.io"

az acr login --name $registryName
# notation login $server # if you don't use Azure Container Registry

# push a hello-world image for signing
docker pull hello-world:latest
docker tag hello-world:latest $server/hello-world:v1
docker push $server/hello-world:v1
```
9. Sign the image with an external certificate bundle (`$certBundlePath`) including the intermediate certificates and a root certificate in PEM format. You may fetch the certificate bundle from your CA official website.
```sh
notation key add --plugin azure-kv --id $keyID akv-key --default
notation sign $server/hello-world:v1 --plugin-config=ca_certs=$certBundlePath
```

The following example output shows the artifact is successfully signed.
```
Warning: Always sign the artifact using digest(@sha256:...) rather than a tag(:v1) because tags are mutable and a tag reference can point to a different artifact than the one signed.
Successfully signed notation.azurecr.io/hello-world@sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4
```
10. Signature verification with Notation needs the root certificate of your CA in the trust store and a `trustpolicy.json` file in Notation configuration directory:
```sh
# add root certificate ($rootCertPath) to notation trust store
notation cert add --type ca --store trusted $rootCertPath

# add notation trust policy
notationConfigDir="${HOME}/.config/notation" # for Linux and WSL
# notationConfigDir="${HOME}/Library/Application Support/notation" # for macOS

mkdir -p $notationConfigDir
cat <<EOF > $notationConfigDir/trustpolicy.json
{
"version": "1.0",
"trustPolicies": [
{
"name": "trust-policy-example",
"registryScopes": [ "*" ],
"signatureVerification": {
"level" : "strict"
},
"trustStores": [ "ca:trusted" ],
"trustedIdentities": [
"*"
]
}
]
}
EOF
chmod 600 $notationConfigDir/trustpolicy.json
```
11. Verify the signature associated with the image:
```
notation verify $server/hello-world:v1
```
The following output shows the artifact is successfully verified.
```
Warning: Always verify the artifact using digest(@sha256:...) rather than a tag(:v1) because resolved digest may not point to the same signed artifact, as tags are mutable.
Successfully verified signature for notation.azurecr.io/hello-world@sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4
```
129 changes: 129 additions & 0 deletions docs/self-signed-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Sign and verify an artifact with a self-signed Azure Key Vault certificate
> **Warning** Using self-signed certificates are intended for development and testing. Outside of development and testing, a certificate from a trusted CA is recommended.

> **Note** The following guide can be executed on Linux bash, macOS Zsh and Windows WSL
1. [Install the Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli)
2. Log in using the Azure CLI, set the subscription, and confirm the `GetCertificate` and `Sign` permission have been granted to your role:
```sh
az login
az account set --subscription $subscriptionID
```
3. Create an Azure Key Vault:
```sh
resourceGroup=<your-resource-group-name>
keyVault=<your-key-vault-name>
location=westus
certName=notationSelfSignedCert

# create a resource group
az group create -n $resourceGroup -l $location

# create a Azure Key Vault
az keyvault create -l $location -n $keyVault --resource-group $resourceGroup
```
4. create a self-signed certificate:
```sh
# generate certificate policy
cat <<EOF > ./selfSignedPolicy.json
{
"issuerParameters": {
"certificateTransparency": null,
"name": "Self"
},
"keyProperties": {
"curve": null,
"exportable": false,
"keySize": 2048,
"keyType": "RSA",
"reuseKey": true
},
"secretProperties": {
"contentType": "application/x-pem-file"
},
"x509CertificateProperties": {
"ekus": [
"1.3.6.1.5.5.7.3.3"
],
"keyUsage": [
"digitalSignature"
],
"subject": "CN=Test-Signer,C=US,ST=WA,O=notation",
"validityInMonths": 12
}
}
EOF

# create self-signed certificate
az keyvault certificate create -n $certName --vault-name $keyVault -p @selfSignedPolicy.json

# get the key identifier
keyID=$(az keyvault certificate show -n $certName --vault-name $keyVault --query 'kid' -o tsv)
```
5. [Create an Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-get-started-portal?tabs=azure-cli). The remaining steps use the example login server `<registry-name>.azurecr.io`, but you must substitute your own login server value.
6. Log in to container registry and push an image for signing:
```sh
registryName="<registry-name>"
server="${registryName}.azurecr.io"

az acr login --name $registryName
# notation login $server # if you don't use Azure Container Registry

# push a hello-world image for signing
docker pull hello-world:latest
docker tag hello-world:latest $server/hello-world:v1
docker push $server/hello-world:v1
```
7. Sign the container image with Notation:
```sh
notation key add --plugin azure-kv --id $keyID akv-key --default
notation sign $server/hello-world:v1
```

The following example output shows the artifact is successfully signed.
```
Warning: Always sign the artifact using digest(@sha256:...) rather than a tag(:v1) because tags are mutable and a tag reference can point to a different artifact than the one signed.
Successfully signed notation.azurecr.io/hello-world@sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4
```
8. Add the certificate to your trust store and the `trustpolicy.json` to Notation configuration directory:
```sh
cat <<EOF > ./selfSignedCert.crt
-----BEGIN CERTIFICATE-----
$(az keyvault certificate show -n $certName --vault-name $keyVault --query 'cer' -o tsv)
-----END CERTIFICATE-----
EOF
notation cert add --type ca --store selfSigned ./selfSignedCert.crt

# add notation trust policy
notationConfigDir="${HOME}/.config/notation" # for Linux and WSL
# notationConfigDir="${HOME}/Library/Application Support/notation" # for macOS

mkdir -p $notationConfigDir
cat <<EOF > $notationConfigDir/trustpolicy.json
{
"version": "1.0",
"trustPolicies": [
{
"name": "trust-policy-example",
"registryScopes": [ "*" ],
"signatureVerification": {
"level" : "strict"
},
"trustStores": [ "ca:selfSigned" ],
"trustedIdentities": [
"*"
]
}
]
}
EOF
chmod 600 $notationConfigDir/trustpolicy.json
```
9. Verify the signature associated with the image:
```sh
notation verify $server/hello-world:v1
```
The following output shows the artifact is successfully verified.
```
Warning: Always verify the artifact using digest(@sha256:...) rather than a tag(:v1) because resolved digest may not point to the same signed artifact, as tags are mutable.
Successfully verified signature for notation.azurecr.io/hello-world@sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4
```
6 changes: 3 additions & 3 deletions internal/keyvault/keyvault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type keyVault struct {
err error
}

func (s *keyVault) Sign(ctx context.Context, name string, version string, parameters azkeys.SignParameters, options *azkeys.SignOptions) (azkeys.SignResponse, error) {
func (s *keyVault) Sign(_ context.Context, _ string, _ string, _ azkeys.SignParameters, _ *azkeys.SignOptions) (azkeys.SignResponse, error) {
return s.resp, s.err
}

Expand Down Expand Up @@ -142,7 +142,7 @@ type certificateVault struct {
err error
}

func (s *certificateVault) GetCertificate(ctx context.Context, certificateName string, certificateVersion string, options *azcertificates.GetCertificateOptions) (azcertificates.GetCertificateResponse, error) {
func (s *certificateVault) GetCertificate(_ context.Context, _ string, _ string, _ *azcertificates.GetCertificateOptions) (azcertificates.GetCertificateResponse, error) {
return s.resp, s.err
}

Expand Down Expand Up @@ -191,7 +191,7 @@ type secretVault struct {
err error
}

func (s *secretVault) GetSecret(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) {
func (s *secretVault) GetSecret(_ context.Context, _ string, _ string, _ *azsecrets.GetSecretOptions) (azsecrets.GetSecretResponse, error) {
return s.resp, s.err
}

Expand Down