feat: add versionless key identifier support (#181)
Feat: - added versionless key/certificate identifier support Test: - added unit test - added E2E test Docs: - added tips for versionless id feature - fixed NOTE marks Resolves #180 #178 Signed-off-by: Junjie Gao <junjiegao@microsoft.com> --------- Signed-off-by: Junjie Gao <junjiegao@microsoft.com>
This commit is contained in:
Родитель
38be1cc281
Коммит
f82c165bb5
|
@ -169,7 +169,7 @@ namespace Notation.Plugin.AzureKeyVault.Command.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void RunAsync_NoSecertsGetPermission()
|
||||
public async Task RunAsync_NoSecertsGetPermission()
|
||||
{
|
||||
// Arrange
|
||||
var keyId = "https://testvault.vault.azure.net/keys/testkey/123";
|
||||
|
@ -196,7 +196,7 @@ namespace Notation.Plugin.AzureKeyVault.Command.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void RunAsync_OtherRequestFailedException()
|
||||
public async Task RunAsync_OtherRequestFailedException()
|
||||
{
|
||||
// Arrange
|
||||
var keyId = "https://testvault.vault.azure.net/keys/testkey/123";
|
||||
|
@ -223,7 +223,7 @@ namespace Notation.Plugin.AzureKeyVault.Command.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void RunAsync_SelfSignedWithCaCerts()
|
||||
public async Task RunAsync_SelfSignedWithCaCerts()
|
||||
{
|
||||
// Arrange
|
||||
var keyId = "https://testvault.vault.azure.net/keys/testkey/123";
|
||||
|
|
|
@ -47,21 +47,48 @@ namespace Notation.Plugin.AzureKeyVault.Client.Tests
|
|||
Assert.Equal($"{keyVaultUrl}/keys/{name}/{version}", keyVaultClient.KeyId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestConstructorWithVersionlessKey()
|
||||
{
|
||||
string keyVaultUrl = "https://myvault.vault.azure.net";
|
||||
string name = "my-key";
|
||||
|
||||
KeyVaultClient keyVaultClient = new KeyVaultClient(keyVaultUrl, name, null, Credentials.GetCredentials(defaultCredentialType));
|
||||
Assert.Equal(name, keyVaultClient.Name);
|
||||
Assert.Null(keyVaultClient.Version);
|
||||
Assert.Equal($"{keyVaultUrl}/keys/{name}", keyVaultClient.KeyId);
|
||||
|
||||
keyVaultClient = new KeyVaultClient($"{keyVaultUrl}/keys/{name}", Credentials.GetCredentials(defaultCredentialType));
|
||||
Assert.Equal(name, keyVaultClient.Name);
|
||||
Assert.Null(keyVaultClient.Version);
|
||||
Assert.Equal($"{keyVaultUrl}/keys/{name}", keyVaultClient.KeyId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("https://myvault.vault.azure.net/invalid/my-key/123")]
|
||||
[InlineData("https://myvault.vault.azure.net/keys/my-key")]
|
||||
[InlineData("https://myvault.vault.azure.net/keys/my-key/")]
|
||||
[InlineData("http://myvault.vault.azure.net/keys/my-key/123")]
|
||||
[InlineData("https://myvault.vault.azure.net/keys")]
|
||||
[InlineData("https://myvault.vault.azure.net/invalid/my-key/123/1234")]
|
||||
public void TestConstructorWithInvalidKeyId(string invalidKeyId)
|
||||
{
|
||||
Assert.Throws<ValidationException>(() => new KeyVaultClient(invalidKeyId, Credentials.GetCredentials(defaultCredentialType)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", "", "")]
|
||||
[InlineData("https://myvault.vault.azure.net", "", "")]
|
||||
[InlineData("https://myvault.vault.azure.net", "my-key", "")]
|
||||
public void TestConstructorWithInvalidArguments(string keyVaultUrl, string name, string? version)
|
||||
{
|
||||
Assert.Throws<ValidationException>(() => new KeyVaultClient(keyVaultUrl, name, version, Credentials.GetCredentials(defaultCredentialType)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
public void TestConstructorWithEmptyKeyId(string invalidKeyId)
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new KeyVaultClient(invalidKeyId, Credentials.GetCredentials(defaultCredentialType)));
|
||||
Assert.Throws<ValidationException>(() => new KeyVaultClient(invalidKeyId, Credentials.GetCredentials(defaultCredentialType)));
|
||||
}
|
||||
|
||||
private class TestableKeyVaultClient : KeyVaultClient
|
||||
|
@ -72,7 +99,7 @@ namespace Notation.Plugin.AzureKeyVault.Client.Tests
|
|||
this._cryptoClient = new Lazy<CryptographyClient>(() => cryptoClient);
|
||||
}
|
||||
|
||||
public TestableKeyVaultClient(string keyVaultUrl, string name, string version, CertificateClient certificateClient, TokenCredential credenital)
|
||||
public TestableKeyVaultClient(string keyVaultUrl, string name, string? version, CertificateClient certificateClient, TokenCredential credenital)
|
||||
: base(keyVaultUrl, name, version, credenital)
|
||||
{
|
||||
this._certificateClient = new Lazy<CertificateClient>(() => certificateClient);
|
||||
|
@ -103,6 +130,15 @@ namespace Notation.Plugin.AzureKeyVault.Client.Tests
|
|||
return new TestableKeyVaultClient("https://fake.vault.azure.net", "fake-certificate", "123", mockCertificateClient.Object, Credentials.GetCredentials(defaultCredentialType));
|
||||
}
|
||||
|
||||
private TestableKeyVaultClient CreateMockedKeyVaultClient(KeyVaultCertificateWithPolicy certWithPolicy)
|
||||
{
|
||||
var mockCertificateClient = new Mock<CertificateClient>(new Uri("https://fake.vault.azure.net/certificates/fake-certificate/123"), new Mock<TokenCredential>().Object);
|
||||
mockCertificateClient.Setup(c => c.GetCertificateAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(Response.FromValue(certWithPolicy, new Mock<Response>().Object));
|
||||
|
||||
return new TestableKeyVaultClient("https://fake.vault.azure.net", "fake-certificate", null, mockCertificateClient.Object, Credentials.GetCredentials(defaultCredentialType));
|
||||
}
|
||||
|
||||
private TestableKeyVaultClient CreateMockedKeyVaultClient(KeyVaultSecret secret)
|
||||
{
|
||||
var mockSecretClient = new Mock<SecretClient>(new Uri("https://fake.vault.azure.net/secrets/fake-secret/123"), new Mock<TokenCredential>().Object);
|
||||
|
@ -158,11 +194,6 @@ namespace Notation.Plugin.AzureKeyVault.Client.Tests
|
|||
public async Task GetCertificateAsync_ReturnsCertificate()
|
||||
{
|
||||
var testCertificate = new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "TestData", "rsa_2048.crt"));
|
||||
var signResult = CryptographyModelFactory.SignResult(
|
||||
keyId: "https://fake.vault.azure.net/keys/fake-key/123",
|
||||
signature: new byte[] { 1, 2, 3 },
|
||||
algorithm: SignatureAlgorithm.RS384);
|
||||
|
||||
var keyVaultCertificate = CertificateModelFactory.KeyVaultCertificate(
|
||||
properties: CertificateModelFactory.CertificateProperties(version: "123"),
|
||||
cer: testCertificate.RawData);
|
||||
|
@ -176,6 +207,22 @@ namespace Notation.Plugin.AzureKeyVault.Client.Tests
|
|||
Assert.Equal(testCertificate.RawData, certificate.RawData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVersionlessCertificateAsync_ReturnCertificate()
|
||||
{
|
||||
var testCertificate = new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "TestData", "rsa_2048.crt"));
|
||||
var keyVaultCertificateWithPolicy = CertificateModelFactory.KeyVaultCertificateWithPolicy(
|
||||
properties: CertificateModelFactory.CertificateProperties(version: "123"),
|
||||
cer: testCertificate.RawData);
|
||||
|
||||
var keyVaultClient = CreateMockedKeyVaultClient(keyVaultCertificateWithPolicy);
|
||||
var certificate = await keyVaultClient.GetCertificateAsync();
|
||||
|
||||
Assert.NotNull(certificate);
|
||||
Assert.IsType<X509Certificate2>(certificate);
|
||||
Assert.Equal(testCertificate.RawData, certificate.RawData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCertificateAsyncThrowValidationException()
|
||||
{
|
||||
|
@ -191,7 +238,7 @@ namespace Notation.Plugin.AzureKeyVault.Client.Tests
|
|||
|
||||
var keyVaultClient = CreateMockedKeyVaultClient(keyVaultCertificate);
|
||||
|
||||
await Assert.ThrowsAsync<ValidationException>(async () => await keyVaultClient.GetCertificateAsync());
|
||||
await Assert.ThrowsAsync<PluginException>(keyVaultClient.GetCertificateAsync);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Notation.Plugin.AzureKeyVault.Command
|
|||
{
|
||||
private DescribeKeyRequest _request;
|
||||
private IKeyVaultClient _keyVaultClient;
|
||||
private const string invalidInputError = "Invalid input. The valid input format is '{\"contractVersion\":\"1.0\",\"keyId\":\"https://<vaultname>.vault.azure.net/<keys|certificate>/<name>/<version>\"}'";
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to create DescribeKey object from JSON string.
|
||||
|
@ -23,7 +22,7 @@ namespace Notation.Plugin.AzureKeyVault.Command
|
|||
var request = JsonSerializer.Deserialize(inputJson, DescribeKeyRequestContext.Default.DescribeKeyRequest);
|
||||
if (request == null)
|
||||
{
|
||||
throw new ValidationException(invalidInputError);
|
||||
throw new ValidationException("Failed to parse the request in JSON format. Please contact Notation maintainers to resolve the issue.");
|
||||
}
|
||||
this._request = request;
|
||||
this._keyVaultClient = new KeyVaultClient(
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Notation.Plugin.AzureKeyVault.Command
|
|||
var request = JsonSerializer.Deserialize(inputJson, GenerateSignatureRequestContext.Default.GenerateSignatureRequest);
|
||||
if (request == null)
|
||||
{
|
||||
throw new ValidationException("Invalid input");
|
||||
throw new ValidationException("Failed to parse the request in JSON format. Please contact Notation maintainers to resolve the issue.");
|
||||
}
|
||||
this._request = request;
|
||||
this._keyVaultClient = new KeyVaultClient(
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Notation.Plugin.AzureKeyVault.Client
|
|||
/// <summary>
|
||||
/// A helper record to store KeyVault metadata.
|
||||
/// </summary>
|
||||
private record KeyVaultMetadata(string KeyVaultUrl, string Name, string Version);
|
||||
private record KeyVaultMetadata(string KeyVaultUrl, string Name, string? Version);
|
||||
|
||||
// Certificate client (lazy initialization)
|
||||
// Protected for unit test
|
||||
|
@ -43,50 +43,52 @@ namespace Notation.Plugin.AzureKeyVault.Client
|
|||
protected Lazy<CryptographyClient> _cryptoClient;
|
||||
// Secret client (lazy initialization)
|
||||
protected Lazy<SecretClient> _secretClient;
|
||||
// Error message for invalid input
|
||||
private const string INVALID_INPUT_ERROR_MSG = "Invalid input. The valid input format is '{\"contractVersion\":\"1.0\",\"keyId\":\"https://<vaultname>.vault.azure.net/<keys|certificate>/<name>/<version>\"}'";
|
||||
|
||||
// Key name or certificate name
|
||||
private string _name;
|
||||
// Key version or certificate version
|
||||
private string _version;
|
||||
private string? _version;
|
||||
// Key identifier (e.g. https://<vaultname>.vault.azure.net/keys/<name>/<version>)
|
||||
private string _keyId;
|
||||
|
||||
// Internal getters for unit test
|
||||
internal string Name => _name;
|
||||
internal string Version => _version;
|
||||
internal string? Version => _version;
|
||||
internal string KeyId => _keyId;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to create AzureKeyVault object from keyVaultUrl, name
|
||||
/// and version.
|
||||
/// </summary>
|
||||
public KeyVaultClient(string keyVaultUrl, string name, string version, TokenCredential credential)
|
||||
public KeyVaultClient(string keyVaultUrl, string name, string? version, TokenCredential credential)
|
||||
{
|
||||
if (string.IsNullOrEmpty(keyVaultUrl))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(keyVaultUrl), "KeyVaultUrl must not be null or empty");
|
||||
throw new ValidationException("Key vault URL must not be null or empty");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name), "KeyName must not be null or empty");
|
||||
throw new ValidationException("Key name must not be null or empty");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(version))
|
||||
if (version != null && version == string.Empty)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(version), "KeyVersion must not be null or empty");
|
||||
throw new ValidationException("Key version must not be empty");
|
||||
}
|
||||
|
||||
this._name = name;
|
||||
this._version = version;
|
||||
this._keyId = $"{keyVaultUrl}/keys/{name}/{version}";
|
||||
_name = name;
|
||||
_version = version;
|
||||
_keyId = $"{keyVaultUrl}/keys/{name}";
|
||||
if (version != null)
|
||||
{
|
||||
_keyId = $"{_keyId}/{version}";
|
||||
}
|
||||
|
||||
// initialize credential and lazy clients
|
||||
this._certificateClient = new Lazy<CertificateClient>(() => new CertificateClient(new Uri(keyVaultUrl), credential));
|
||||
this._cryptoClient = new Lazy<CryptographyClient>(() => new CryptographyClient(new Uri(_keyId), credential));
|
||||
this._secretClient = new Lazy<SecretClient>(() => new SecretClient(new Uri(keyVaultUrl), credential));
|
||||
_certificateClient = new Lazy<CertificateClient>(() => new CertificateClient(new Uri(keyVaultUrl), credential));
|
||||
_cryptoClient = new Lazy<CryptographyClient>(() => new CryptographyClient(new Uri(_keyId), credential));
|
||||
_secretClient = new Lazy<SecretClient>(() => new SecretClient(new Uri(keyVaultUrl), credential));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -115,30 +117,36 @@ namespace Notation.Plugin.AzureKeyVault.Client
|
|||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id), "Id must not be null or empty");
|
||||
throw new ValidationException("Input passed to \"--id\" must not be empty");
|
||||
}
|
||||
|
||||
var uri = new Uri(id);
|
||||
var uri = new Uri(id.TrimEnd('/'));
|
||||
// Validate uri
|
||||
if (uri.Segments.Length != 4)
|
||||
if (uri.Segments.Length < 3 || uri.Segments.Length > 4)
|
||||
{
|
||||
throw new ValidationException(INVALID_INPUT_ERROR_MSG);
|
||||
throw new ValidationException("Invalid input passed to \"--id\". Please follow this format to input the ID \"https://<vault-name>.vault.azure.net/certificates/<certificate-name>/[certificate-version]\"");
|
||||
}
|
||||
|
||||
if (uri.Segments[1] != "keys/" && uri.Segments[1] != "certificates/")
|
||||
var type = uri.Segments[1].TrimEnd('/');
|
||||
if (type != "keys" && type != "certificates")
|
||||
{
|
||||
throw new ValidationException(INVALID_INPUT_ERROR_MSG);
|
||||
throw new ValidationException($"Unsupported key vualt object type {type}.");
|
||||
}
|
||||
|
||||
if (uri.Scheme != "https")
|
||||
{
|
||||
throw new ValidationException(INVALID_INPUT_ERROR_MSG);
|
||||
throw new ValidationException($"Unsupported scheme {uri.Scheme}. The scheme must be https.");
|
||||
}
|
||||
|
||||
string? version = null;
|
||||
if (uri.Segments.Length == 4)
|
||||
{
|
||||
version = uri.Segments[3].TrimEnd('/');
|
||||
}
|
||||
return new KeyVaultMetadata(
|
||||
KeyVaultUrl: $"{uri.Scheme}://{uri.Host}",
|
||||
Name: uri.Segments[2].TrimEnd('/'),
|
||||
Version: uri.Segments[3].TrimEnd('/')
|
||||
Version: version
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -148,9 +156,10 @@ namespace Notation.Plugin.AzureKeyVault.Client
|
|||
public async Task<byte[]> SignAsync(SignatureAlgorithm algorithm, byte[] payload)
|
||||
{
|
||||
var signResult = await _cryptoClient.Value.SignDataAsync(algorithm, payload);
|
||||
if (signResult.KeyId != _keyId)
|
||||
|
||||
if (!string.IsNullOrEmpty(_version) && signResult.KeyId != _keyId)
|
||||
{
|
||||
throw new PluginException($"Invalid keys identifier. The user provides {_keyId} but the response contains {signResult.KeyId} as the keys");
|
||||
throw new PluginException($"Invalid key identifier. User required {_keyId} does not match {signResult.KeyId} in response. Please ensure the provided key identifier is correct.");
|
||||
}
|
||||
|
||||
if (signResult.Algorithm != algorithm)
|
||||
|
@ -166,17 +175,25 @@ namespace Notation.Plugin.AzureKeyVault.Client
|
|||
/// </summary>
|
||||
public async Task<X509Certificate2> GetCertificateAsync()
|
||||
{
|
||||
var cert = await _certificateClient.Value.GetCertificateVersionAsync(_name, _version);
|
||||
|
||||
// If the version is invalid, the cert will be fallback to
|
||||
// the latest. So if the version is not the same as the
|
||||
// requested version, it means the version is invalid.
|
||||
if (cert.Value.Properties.Version != _version)
|
||||
KeyVaultCertificate cert;
|
||||
if (string.IsNullOrEmpty(_version))
|
||||
{
|
||||
throw new ValidationException($"Invalid certificate version. The user provides {_version} but the response contains {cert.Value.Properties.Version} as the version");
|
||||
// If the version is not specified, get the latest version
|
||||
cert = (await _certificateClient.Value.GetCertificateAsync(_name)).Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
cert = (await _certificateClient.Value.GetCertificateVersionAsync(_name, _version)).Value;
|
||||
|
||||
return new X509Certificate2(cert.Value.Cer);
|
||||
// If the version is invalid, the cert will be fallback to
|
||||
// the latest. So if the version is not the same as the
|
||||
// requested version, it means the version is invalid.
|
||||
if (cert.Properties.Version != _version)
|
||||
{
|
||||
throw new PluginException($"The version specified in the request is {_version} but the version retrieved from Azure Key Vault is {cert.Properties.Version}. Please ensure the version is correct.");
|
||||
}
|
||||
}
|
||||
return new X509Certificate2(cert.Cer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -31,9 +31,9 @@
|
|||
--secret-permissions get \
|
||||
--object-id "$userId"
|
||||
```
|
||||
> [!NOTE]
|
||||
> The script assigns the permission to the current user, and you can also assign the permission to your [managed identity](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) or [service principal](https://learn.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals?tabs=browser).
|
||||
> To know more about permission management, please visit [Azure Key Vualt access policy](https://learn.microsoft.com/azure/key-vault/general/assign-access-policy?tabs=azure-portal).
|
||||
> [!NOTE]
|
||||
> The script assigns the permission to the current user, and you can also assign the permission to your [managed identity](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) or [service principal](https://learn.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals?tabs=browser).
|
||||
> To know more about permission management, please visit [Azure Key Vualt access policy](https://learn.microsoft.com/azure/key-vault/general/assign-access-policy?tabs=azure-portal).
|
||||
4. Create a Certificate Signing Request (CSR):
|
||||
|
||||
Generate certificate policy:
|
||||
|
@ -100,8 +100,8 @@
|
|||
certChainPath="${certName}-chain.crt"
|
||||
cat "$signedCertPath" ca.crt > "$certChainPath"
|
||||
```
|
||||
> [!NOTE]
|
||||
> If you have merged your certificate to Azure Key Vault without certificate chain or you don't want the plugin access your certificate chain with the `Secrets Get` permission, please use [ca_certs](./plugin-config.md#ca_certs) plugin configuration argument instead.
|
||||
> [!NOTE]
|
||||
> If you have merged your certificate to Azure Key Vault without certificate chain or you don't want the plugin access your certificate chain with the `Secrets Get` permission, please use [ca_certs](./plugin-config.md#ca_certs) plugin configuration argument instead.
|
||||
|
||||
6. After you get the leaf certificate, you can merge the certificate chain (file at `$certChainPath`) to your Azure Key Vault:
|
||||
```sh
|
||||
|
@ -111,6 +111,8 @@
|
|||
```sh
|
||||
keyID=$(az keyvault certificate show -n $certName --vault-name $keyVault --query 'kid' -o tsv)
|
||||
```
|
||||
> [!TIP]
|
||||
> Versionless KeyID is also supported. For example: https://{vault-name}.vault.azure.net/certificates/{certificate-name}
|
||||
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
|
||||
|
|
|
@ -33,9 +33,9 @@
|
|||
--certificates-permissions get \
|
||||
--upn "$userId"
|
||||
```
|
||||
> [!NOTE]
|
||||
> The script assigns the permission to the current user, and you can also assign the permission to your [managed identity](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) or [service principal](https://learn.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals?tabs=browser).
|
||||
> To know more about permission management, please visit [Azure Key Vualt access policy](https://learn.microsoft.com/azure/key-vault/general/assign-access-policy?tabs=azure-portal).
|
||||
> [!NOTE]
|
||||
> The script assigns the permission to the current user, and you can also assign the permission to your [managed identity](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) or [service principal](https://learn.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals?tabs=browser).
|
||||
> To know more about permission management, please visit [Azure Key Vualt access policy](https://learn.microsoft.com/azure/key-vault/general/assign-access-policy?tabs=azure-portal).
|
||||
4. create a self-signed certificate:
|
||||
```sh
|
||||
# generate certificate policy
|
||||
|
@ -74,6 +74,8 @@
|
|||
# get the key identifier
|
||||
keyID=$(az keyvault certificate show -n $certName --vault-name $keyVault --query 'kid' -o tsv)
|
||||
```
|
||||
> [!TIP]
|
||||
> Versionless KeyID is also supported. For example: https://{vault-name}.vault.azure.net/certificates/{certificate-name}
|
||||
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
|
||||
|
|
|
@ -35,6 +35,26 @@ runs:
|
|||
target_artifact_reference: localhost:5000/hello-world:v1
|
||||
signature_format: cose
|
||||
plugin_config: 'self_signed=true'
|
||||
- name: self-signed versionless pem certificate
|
||||
uses: notaryproject/notation-action/sign@v1
|
||||
with:
|
||||
plugin_name: azure-kv
|
||||
plugin_url: ${{ inputs.pluginDownloadURL }}
|
||||
plugin_checksum: ${{ inputs.pluginChecksum }}
|
||||
key_id: https://acrci-test-kv.vault.azure.net/keys/self-signed-pem
|
||||
target_artifact_reference: localhost:5000/hello-world:v1
|
||||
signature_format: cose
|
||||
plugin_config: 'self_signed=true'
|
||||
- name: self-signed versionless pem certificate id ends with slash
|
||||
uses: notaryproject/notation-action/sign@v1
|
||||
with:
|
||||
plugin_name: azure-kv
|
||||
plugin_url: ${{ inputs.pluginDownloadURL }}
|
||||
plugin_checksum: ${{ inputs.pluginChecksum }}
|
||||
key_id: https://acrci-test-kv.vault.azure.net/keys/self-signed-pem/
|
||||
target_artifact_reference: localhost:5000/hello-world:v1
|
||||
signature_format: cose
|
||||
plugin_config: 'self_signed=true'
|
||||
- name: imported ca-issued pem
|
||||
uses: notaryproject/notation-action/sign@v1
|
||||
with:
|
||||
|
@ -109,6 +129,26 @@ runs:
|
|||
target_artifact_reference: localhost:5000/hello-world:v1
|
||||
signature_format: cose
|
||||
plugin_config: 'ca_certs=./test/e2e/certs/cert-bundle.pem'
|
||||
|
||||
# failed test cases
|
||||
- name: invalid certificate version
|
||||
continue-on-error: true
|
||||
id: invalid-certificate-version
|
||||
uses: notaryproject/notation-action/sign@v1
|
||||
with:
|
||||
plugin_name: azure-kv
|
||||
plugin_url: ${{ inputs.pluginDownloadURL }}
|
||||
plugin_checksum: ${{ inputs.pluginChecksum }}
|
||||
key_id: https://acrci-test-kv.vault.azure.net/keys/self-signed-pem/invalid
|
||||
target_artifact_reference: localhost:5000/hello-world:v1
|
||||
signature_format: cose
|
||||
plugin_config: 'self_signed=true'
|
||||
- name: 'Should Fail: invalid certificate version'
|
||||
if: steps.invalid-certificate-version.outcome != 'failure'
|
||||
run: |
|
||||
echo "invalid certificate version should failed, but succeeded."
|
||||
exit 1
|
||||
shell: bash
|
||||
- name: partial pem cert chain with local invalid local cert bundle
|
||||
continue-on-error: true
|
||||
id: partial-pem-cert-chain-invalid-local-cert-bundle
|
||||
|
@ -255,4 +295,4 @@ runs:
|
|||
signature_format: cose
|
||||
plugin_config: |
|
||||
credential_type=azurecli
|
||||
self_signed=true
|
||||
self_signed=true
|
||||
|
|
Загрузка…
Ссылка в новой задаче