This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new a6a8441fb16 NIFI-15667 Supported plain text secrets in AWS Secrets
Manager Parameter Provider (#10962)
a6a8441fb16 is described below
commit a6a8441fb16e68899f84352b47f1d5274bcc5760
Author: Pierre Villard <[email protected]>
AuthorDate: Tue Mar 10 19:28:23 2026 +0100
NIFI-15667 Supported plain text secrets in AWS Secrets Manager Parameter
Provider (#10962)
Signed-off-by: David Handermann <[email protected]>
---
.../aws/AwsSecretsManagerParameterProvider.java | 31 ++++----
.../additionalDetails.md | 16 +++++
.../TestAwsSecretsManagerParameterProvider.java | 84 ++++++++++++++++++++++
3 files changed, 115 insertions(+), 16 deletions(-)
diff --git
a/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/java/org/apache/nifi/parameter/aws/AwsSecretsManagerParameterProvider.java
b/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/java/org/apache/nifi/parameter/aws/AwsSecretsManagerParameterProvider.java
index e1371aa95b7..ff932a29836 100644
---
a/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/java/org/apache/nifi/parameter/aws/AwsSecretsManagerParameterProvider.java
+++
b/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/java/org/apache/nifi/parameter/aws/AwsSecretsManagerParameterProvider.java
@@ -289,31 +289,30 @@ public class AwsSecretsManagerParameterProvider extends
AbstractParameterProvide
return groups;
}
- final ObjectNode secretObject =
parseSecret(getSecretValueResponse.secretString());
+ final String secretString = getSecretValueResponse.secretString();
+ final ObjectNode secretObject = parseSecret(secretString);
if (secretObject == null) {
- getLogger().debug("Secret [{}] is not in the expected JSON
key/value format", secretName);
- return groups;
- }
-
- for (final Map.Entry<String, JsonNode> field :
secretObject.properties()) {
- final String parameterName = field.getKey();
- final JsonNode valueNode = field.getValue();
- if (!valueNode.isValueNode() || valueNode.isNull()) {
- getLogger().debug("Secret [{}] Parameter [{}] is null or
not a supported value type", secretName, parameterName);
- continue;
+ getLogger().debug("Secret [{}] is not a JSON object, treating
as plain text parameter", secretName);
+ parameters.add(createParameter(secretName, secretString,
tags));
+ } else {
+ for (final Map.Entry<String, JsonNode> field :
secretObject.properties()) {
+ final String parameterName = field.getKey();
+ final JsonNode valueNode = field.getValue();
+ if (!valueNode.isValueNode() || valueNode.isNull()) {
+ getLogger().debug("Secret [{}] Parameter [{}] is null
or not a supported value type", secretName, parameterName);
+ continue;
+ }
+ parameters.add(createParameter(parameterName,
valueNode.asText(), tags));
}
- final String parameterValue = valueNode.asText();
-
- parameters.add(createParameter(parameterName, parameterValue,
tags));
}
groups.add(new ParameterGroup(secretName, parameters));
return groups;
} catch (final ResourceNotFoundException e) {
- throw new IllegalStateException(String.format("Secret %s not
found", secretName), e);
+ throw new IllegalStateException("Secret %s not
found".formatted(secretName), e);
} catch (final SecretsManagerException e) {
- throw new IllegalStateException("Error retrieving secret " +
secretName, e);
+ throw new IllegalStateException("Error retrieving secret
%s".formatted(secretName), e);
}
}
diff --git
a/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/resources/docs/org.apache.nifi.parameter.aws.AwsSecretsManagerParameterProvider/additionalDetails.md
b/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/resources/docs/org.apache.nifi.parameter.aws.AwsSecretsManagerParameterProvider/additionalDetails.md
index 842f11ee4c8..af25c4a01e1 100644
---
a/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/resources/docs/org.apache.nifi.parameter.aws.AwsSecretsManagerParameterProvider/additionalDetails.md
+++
b/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/main/resources/docs/org.apache.nifi.parameter.aws.AwsSecretsManagerParameterProvider/additionalDetails.md
@@ -35,6 +35,22 @@ aws secretsmanager create-secret --name "\[Context\]"
--secret-string '{ "\[Para
In this example, \[Context\] should be the intended name of the Parameter
Context, \[Param\] and \[Param2\] should be
parameter names, and \[secretValue\] and \[secretValue2\] should be the values
of each respective parameter.
+### Plain Text Secrets
+
+Secrets that are not stored as JSON key/value pairs are also supported. When a
secret value is not a JSON object (for
+example, a PEM-encoded private key or any other plain text string), it is
treated as a single parameter whose name is the
+secret name and whose value is the entire secret string. The secret name is
also used as the Parameter Context name.
+
+For example, to store a PEM key as a secret:
+
+aws secretsmanager create-secret --name "my-private-key" --secret-string
file://path/to/key.pem
+
+This produces a Parameter Context named "my-private-key" containing a single
parameter also named "my-private-key" with
+the contents of the PEM file as the value.
+
+Both JSON and plain text secrets can be mixed within the same Secret Name
Pattern. Each secret is automatically detected
+and handled according to its format.
+
### Configuring the Parameter Provider
AWS Secrets must be explicitly matched in the "Secret Name Pattern" property
in order for them to be fetched. This
diff --git
a/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/test/java/org/apache/nifi/parameter/aws/TestAwsSecretsManagerParameterProvider.java
b/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/test/java/org/apache/nifi/parameter/aws/TestAwsSecretsManagerParameterProvider.java
index ab1e22c3afa..e5ffa279a8c 100644
---
a/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/test/java/org/apache/nifi/parameter/aws/TestAwsSecretsManagerParameterProvider.java
+++
b/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-parameter-providers/src/test/java/org/apache/nifi/parameter/aws/TestAwsSecretsManagerParameterProvider.java
@@ -310,6 +310,90 @@ public class TestAwsSecretsManagerParameterProvider {
}
}
+ @Test
+ public void testFetchPlainTextSecretEnumeration() throws
InitializationException {
+ final String secretName = "PlainTextSecret";
+ final String plainTextContent = "Lorem ipsum dolor sit amet,
consectetur adipiscing elit";
+
+ final SecretsManagerClient secretsManager =
mock(SecretsManagerClient.class);
+
+ final GetSecretValueResponse response =
GetSecretValueResponse.builder()
+ .name(secretName)
+ .secretString(plainTextContent)
+ .build();
+
when(secretsManager.getSecretValue(argThat(matchesGetSecretValueRequest(secretName)))).thenReturn(response);
+
+ final DescribeSecretResponse describeResponse =
DescribeSecretResponse.builder()
+ .name(secretName)
+ .build();
+
when(secretsManager.describeSecret(argThat(matchesDescribeSecretRequest(secretName)))).thenReturn(describeResponse);
+
+ final List<ParameterGroup> parameterGroups =
runProviderTest(secretsManager, 1,
+ ConfigVerificationResult.Outcome.SUCCESSFUL, "ENUMERATION",
secretName);
+
+ assertEquals(1, parameterGroups.size());
+ final ParameterGroup group = parameterGroups.get(0);
+ assertEquals(secretName, group.getGroupName());
+ assertEquals(1, group.getParameters().size());
+
+ final Parameter parameter = group.getParameters().get(0);
+ assertEquals(secretName, parameter.getDescriptor().getName());
+ assertEquals(plainTextContent, parameter.getValue());
+ }
+
+ @Test
+ public void testFetchMixedJsonAndPlainTextSecretsPattern() throws
InitializationException {
+ final String plainTextSecretName = "PlainTextSecret";
+ final String jsonSecretName = "JsonSecret";
+ final String plainTextContent = "Sed ut perspiciatis unde omnis iste
natus error sit voluptatem";
+ final String jsonContent = "{ \"serverHost\": \"db.example.com\",
\"serverPort\": \"5432\" }";
+
+ final SecretsManagerClient secretsManager =
mock(SecretsManagerClient.class);
+
+ final SecretListEntry plainTextEntry =
SecretListEntry.builder().name(plainTextSecretName).build();
+ final SecretListEntry jsonEntry =
SecretListEntry.builder().name(jsonSecretName).build();
+
+ final ListSecretsResponse firstPage = mock(ListSecretsResponse.class);
+ when(firstPage.secretList()).thenReturn(List.of(plainTextEntry,
jsonEntry));
+ when(firstPage.nextToken()).thenReturn(null);
+
when(secretsManager.listSecrets(argThat(ListSecretsRequestMatcher.hasToken(null)))).thenReturn(firstPage);
+
+ final GetSecretValueResponse plainTextResponse =
GetSecretValueResponse.builder()
+ .name(plainTextSecretName)
+ .secretString(plainTextContent)
+ .build();
+
when(secretsManager.getSecretValue(argThat(matchesGetSecretValueRequest(plainTextSecretName)))).thenReturn(plainTextResponse);
+
+ final GetSecretValueResponse jsonResponse =
GetSecretValueResponse.builder()
+ .name(jsonSecretName)
+ .secretString(jsonContent)
+ .build();
+
when(secretsManager.getSecretValue(argThat(matchesGetSecretValueRequest(jsonSecretName)))).thenReturn(jsonResponse);
+
+ final List<ParameterGroup> parameterGroups =
runProviderTest(secretsManager, 3,
+ ConfigVerificationResult.Outcome.SUCCESSFUL, "PATTERN", null);
+
+ assertEquals(2, parameterGroups.size());
+
+ final ParameterGroup plainTextGroup = parameterGroups.stream()
+ .filter(g -> plainTextSecretName.equals(g.getGroupName()))
+ .findFirst()
+ .orElseThrow();
+ assertEquals(1, plainTextGroup.getParameters().size());
+ assertEquals(plainTextSecretName,
plainTextGroup.getParameters().get(0).getDescriptor().getName());
+ assertEquals(plainTextContent,
plainTextGroup.getParameters().get(0).getValue());
+
+ final ParameterGroup jsonGroup = parameterGroups.stream()
+ .filter(g -> jsonSecretName.equals(g.getGroupName()))
+ .findFirst()
+ .orElseThrow();
+ assertEquals(2, jsonGroup.getParameters().size());
+ final Map<String, String> jsonParams =
jsonGroup.getParameters().stream()
+ .collect(Collectors.toMap(p -> p.getDescriptor().getName(),
Parameter::getValue));
+ assertEquals("db.example.com", jsonParams.get("serverHost"));
+ assertEquals("5432", jsonParams.get("serverPort"));
+ }
+
private AwsSecretsManagerParameterProvider getParameterProvider() {
return spy(new AwsSecretsManagerParameterProvider());
}