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

aws_ssm: StringListParameter.ValueForTypedListParameter to support shared parameters #29292

Closed
2 tasks
Labels
@aws-cdk/aws-ssm Related to AWS Systems Manager closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. guidance Question that needs advice or information. p3 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.

Comments

@anthony-keller
Copy link

Describe the feature

Now that parameter sharing between accounts is a feature, the CDK constructs should support ARN parameter names so that a shared parameter from a different account can be retrieved.

Use Case

I'm attempting to create the required Route53 resources in a multi-account organization. The DNS architecture we're using is:

  • domain-account : contains the registered domain and a hosted zone.
  • workload-account : contains workloads and has a sub-domain of the main domain in domain-account

In order for the CDK to create the required resources, I'm trying to use the following stacks:

WorkloadAccountStack - this stack creates a hosted zone, e.g. dev.domain.com, and creates a StringListParameter with a value of the NS entry of the new hosted zone. The parameter name is _dns_DevNameServers and is in the ADVANCED tier. Additionally, a CfnResourceShare is created to share the parameter with the domain-account.

DomainAccountStack - this stack creates a NS record in the domain.com hosted zone. To do this, the stack must get the value of the _dns_DevNameServers parameter from the workload-account.

AWS docs state that accessing a parameter is done by passing the ARN as the parameter name.

In 2.130 of CDK, I'm using the following code:

    public static string[] ValueForTypedListParameter(Construct scope, string id, string parameterName, Environment environment)
    {
        var parameterArn = Arn.Format(new ArnComponents
        {
            ArnFormat = ArnFormat.COLON_RESOURCE_NAME,
            Partition = AwsArnPartitions.Aws,
            Account = environment.Account,
            Region = environment.Region,
            Service = AwsArnServices.Ssm,
            Resource = AwsArnResources.Parameter,
            ResourceName = parameterName
        });

        var parameter = StringListParameter.FromListParameterAttributes(scope, id, new ListParameterAttributes
        {
            ParameterName = parameterArn
        });

        return parameter.StringListValue;
    }

When attempting to deploy the stack, I get the following error:

Could not determine the resource name from arn: arn:aws:ssm:ap-southeast-2:xxxxxxxxxxxxxx:parameter:_dns_DevNameServers

I believe this is due to using COLON_RESOURCE_NAME as the ArnFormat. I would like to use SLASH_RESOURCE_NAME, however, when using that, the synth process throws an error:

Error: Parameter names must be fully qualified (if they include "/" they must also begin with a "/")

Proposed Solution

At this stage I'm not sure where to start with a solution for this problem.

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

CDK version used

2.130

Environment details (OS name and version, etc.)

Windows 11

@anthony-keller anthony-keller added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels Feb 28, 2024
@github-actions github-actions bot added the @aws-cdk/aws-ssm Related to AWS Systems Manager label Feb 28, 2024
@pahud
Copy link
Contributor

pahud commented Feb 28, 2024

StringListParameter.ValueForTypedListParameter actually creates dynamic reference if you look at its implementation. Based on the answer from Amazon Q, dynamic references do support cross-account access so I think it should be possible for cross account secret reference.

Self-assigned for now. I'll investigate and try to provide some working samples here.

@pahud pahud self-assigned this Feb 28, 2024
@pahud pahud added p2 guidance Question that needs advice or information. effort/medium Medium work item – several days of effort and removed needs-triage This issue or PR still needs to be triaged. labels Feb 28, 2024
@anthony-keller
Copy link
Author

anthony-keller commented Feb 28, 2024

Thanks @pahud . I may be able to use SecretManager rather than Parameter Store. From what I can tell, a secret can be created and can have read permission granted to other accounts. I can then use Secret.FromSecretCompleteArn() to retrieve the value. Using secrets has a cost, so I'm keen to avoid that if possible.

Alternatively, since I'm using Octopus Deploy, any outputs from a CloudFormation template are made available in Powershell. I could write a script to retrieve the value and then use the AWS CLI to create the required NS record in the domain.com hosted zone. Not as elegant as using CDK and CloudFormation stacks, but would achieve the desired result.

I'm actively working on this so will post any progress.

@anthony-keller
Copy link
Author

CloudFormation docs suggest that it might not be possible to dynamically resolve a parameter using an ARN.

Additional considerations to note when using the ssm dynamic reference pattern:

  • Currently, CloudFormation doesn't support cross-account SSM parameter access.

@marksieczkowski
Copy link

I got StringParameter.valueFromLookup to work with a shared parameter.

    const parameterValue = ssm.StringParameter.valueFromLookup(this, Arn.format({
      account: host_account_id,
      partition: 'aws',
      region: this.region,
      resource: 'parameter',
      resourceName: 'parameter_name',
      service: 'ssm',
    }));

But I found it clunky to use because I had to do a synth before I used the value anywhere for it to seed the cdk.context.json with a value or else doing a synth would error on the dummy value.

It would be nice if StringParameter.valueForStringParameter would accept an Arn.

@aarcro
Copy link

aarcro commented Jun 4, 2024

Here's my use case for this feature. We're in an AWS Organization with a central account that builds AMIs, those AMIs are published to our many accounts, and the ARNs for the current versions of the AMIs are populated in SSM parameters that are shared to all accounts. I would like to call ec2.MachineImage.fromSsmParameter(ssmParameterArn, {cachedInContext: false}) with ssmParameterArn already specified as a full ARN since it is shared from a different account.

@pahud
Copy link
Contributor

pahud commented Jun 21, 2024

Please check this working sample.

#30603 (comment)

Let me know if it works for you.(It does for me)

@pahud pahud added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Jun 21, 2024
@pahud pahud removed their assignment Jun 21, 2024
Copy link

This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

@github-actions github-actions bot added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Jun 23, 2024
@github-actions github-actions bot added closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. and removed closing-soon This issue will automatically close in 4 days unless further comments are made. labels Jun 29, 2024
mergify bot pushed a commit that referenced this issue Aug 19, 2024
AWS [introduced](https://aws.amazon.com/about-aws/whats-new/2024/02/aws-systems-manager-parameter-store-cross-account-sharing/) SSM Parameter Store cross-account sharing in Feb 2024. Under the hood, the sharing account has to create an AWS RAM ResourceShare for the principal of the consuming account and the consuming account has to accept the sharing invite. The only approach to access that sharing parameter is through CfnParameter. Dynamic Reference is NOT supported.

This PR adds `StringParameter.fromStringParameterArn()` method so we can use the API like

```ts
const remoteParameterArn = 'arn:aws:ssm:us-east-1:123456789012:parameter/dummyName';

const sharedParam = StringParameter.fromStringParameterArn(scope, id, remoteParameterArn);

new cdk.CfnOutput(this, 'ParamValue', { value: sharedParam.stringValue });
```

Note:

1. The only option to consume sharing parameters in CFN is template parameter. `StringParameter.fromStringParameterArn()` would synthesize CfnParameter like:

```yaml
SharedParameter:
    Description: a shared golden AMI from centralised accounts
    Type: "AWS::SSM::Parameter::Value<String>"
    Default: "arn:aws:ssm:us-east-1:123456789012:parameter/sharedParameterName"
```
And the `Default` value has to be a static string. It can't be an unresolved token.

2. For full use case(sharing, accepting and consuming), check out `integ.parameter-store-string-sharing.ts` for more details.


### Issue # (if applicable)

Closes #29292 

### Reason for this change



### Description of changes



### Description of how you validated changes

Debugger
```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Jest",
      "program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
      "cwd": "${workspaceFolder}/packages/aws-cdk-lib",
      "args": [
        "--verbose",
        "-i",
        "--no-cache",
        "test/parameter.test.ts",
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "skipFiles": [
        "<node_internals>/**"
      ],
      "outFiles": [
        "${workspaceFolder}/**/*.(m|c|)js",
        "!**/node_modules/**"
      ],
    }
  ]
}
```

### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
GavinZZ pushed a commit that referenced this issue Aug 20, 2024
AWS [introduced](https://aws.amazon.com/about-aws/whats-new/2024/02/aws-systems-manager-parameter-store-cross-account-sharing/) SSM Parameter Store cross-account sharing in Feb 2024. Under the hood, the sharing account has to create an AWS RAM ResourceShare for the principal of the consuming account and the consuming account has to accept the sharing invite. The only approach to access that sharing parameter is through CfnParameter. Dynamic Reference is NOT supported.

This PR adds `StringParameter.fromStringParameterArn()` method so we can use the API like

```ts
const remoteParameterArn = 'arn:aws:ssm:us-east-1:123456789012:parameter/dummyName';

const sharedParam = StringParameter.fromStringParameterArn(scope, id, remoteParameterArn);

new cdk.CfnOutput(this, 'ParamValue', { value: sharedParam.stringValue });
```

Note:

1. The only option to consume sharing parameters in CFN is template parameter. `StringParameter.fromStringParameterArn()` would synthesize CfnParameter like:

```yaml
SharedParameter:
    Description: a shared golden AMI from centralised accounts
    Type: "AWS::SSM::Parameter::Value<String>"
    Default: "arn:aws:ssm:us-east-1:123456789012:parameter/sharedParameterName"
```
And the `Default` value has to be a static string. It can't be an unresolved token.

2. For full use case(sharing, accepting and consuming), check out `integ.parameter-store-string-sharing.ts` for more details.


### Issue # (if applicable)

Closes #29292 

### Reason for this change



### Description of changes



### Description of how you validated changes

Debugger
```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Jest",
      "program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
      "cwd": "${workspaceFolder}/packages/aws-cdk-lib",
      "args": [
        "--verbose",
        "-i",
        "--no-cache",
        "test/parameter.test.ts",
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "skipFiles": [
        "<node_internals>/**"
      ],
      "outFiles": [
        "${workspaceFolder}/**/*.(m|c|)js",
        "!**/node_modules/**"
      ],
    }
  ]
}
```

### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-ssm Related to AWS Systems Manager closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. guidance Question that needs advice or information. p3 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.
Projects
None yet
4 participants