Skip to content

Commit

Permalink
feat: Enable creation of strong names for .NET assemblies. (#643)
Browse files Browse the repository at this point in the history
  • Loading branch information
mpiroc authored and rix0rrr committed Sep 11, 2018
1 parent 4db197a commit b6074ba
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 20 deletions.
3 changes: 3 additions & 0 deletions buildspec.yaml
Expand Up @@ -4,6 +4,9 @@ phases:
install:
commands:
- /bin/bash ./install.sh
pre_build:
commands:
- /bin/bash ./fetch-dotnet-snk.sh
build:
commands:
- /bin/bash ./build.sh
Expand Down
61 changes: 61 additions & 0 deletions fetch-dotnet-snk.sh
@@ -0,0 +1,61 @@
#!/bin/bash
set -euo pipefail

# This script retrieves the .snk file needed to create strong names for .NET assemblies.

function echo_usage() {
echo "USAGE: Set the following environment variables, then run ./fetch-dotnet-snk.sh with no arguments."
echo -e "\tDOTNET_STRONG_NAME_ENABLED=true"
echo -e "\tDOTNET_STRONG_NAME_ROLE_ARN=<ARN of a role with access to the secret. You must have iam:AssumeRole permissions for this role.>"
echo -e "\tDOTNET_STRONG_NAME_SECRET_REGION=<The AWS region (i.e. us-east-2) in which in the secret is stored.>"
echo -e "\tDOTNET_STRONG_NAME_SECRET_ID=<The name (i.e. production/my/key) or ARN of the secret containing the .snk file.>"
}

if [ -z ${DOTNET_STRONG_NAME_ENABLED:-} ]; then
echo "Environment variable DOTNET_STRONG_NAME_ENABLED is not set. Skipping strong-name signing."
exit 0
fi

echo "Retrieving SNK..."

apt update -y
apt install jq -y

if [ -z ${DOTNET_STRONG_NAME_ROLE_ARN:-} ]; then
echo "Strong name signing is enabled, but DOTNET_STRONG_NAME_ROLE_ARN is not set."
echo_usage
exit 1
fi

if [ -z ${DOTNET_STRONG_NAME_SECRET_REGION:-}]; then
echo "Strong name signing is enabled, but DOTNET_STRONG_NAME_SECRET_REGION is not set."
echo_usage
exit 1
fi

if [ -z ${DOTNET_STRONG_NAME_SECRET_ID:-} ]; then
echo "Strong name signing is enabled, but DOTNET_STRONG_NAME_SECRET_ID is not set."
echo_usage
exit 1
fi

ROLE=$(aws sts assume-role --region ${DOTNET_STRONG_NAME_SECRET_REGION:-} --role-arn ${DOTNET_STRONG_NAME_ROLE_ARN:-} --role-session-name "jsii-dotnet-snk")
export AWS_ACCESS_KEY_ID=$(echo $ROLE | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $ROLE | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $ROLE | jq .Credentials.SessionToken)

SNK_SECRET=$(aws secretsmanager get-secret-value --region ${DOTNET_STRONG_NAME_SECRET_REGION:-} --secret-id ${DOTNET_STRONG_NAME_SECRET_ID:-})
TMP_DIR=$(mktemp -d)
TMP_KEY="$TMP_DIR/key.snk"
echo $SNK_SECRET | jq -r .SecretBinary | base64 --decode > $TMP_KEY

for PACKAGE_PATH in packages/@aws-cdk/*; do
JSII_PROPERTY=$(cat "$PACKAGE_PATH/package.json" | jq -r .jsii)
if [ -z $JSII_PROPERTY ]; then
continue
fi

cp $TMP_KEY $PACKAGE_PATH
done

rm -rf $TMP_DIR
17 changes: 12 additions & 5 deletions packages/@aws-cdk/aws-dynamodb/lib/table.ts
Expand Up @@ -26,22 +26,28 @@ export interface TableProps {
*/
tableName?: string;

/**
* Whether server-side encryption is enabled.
* @default undefined, server-side encryption is disabled
*/
sseEnabled?: boolean;

/**
* When an item in the table is modified, StreamViewType determines what information
* is written to the stream for this table. Valid values for StreamViewType are:
* @default undefined, streams are disbaled
* @default undefined, streams are disabled
*/
streamSpecification?: StreamViewType;

/**
* AutoScalingProps configuration to configure Read AutoScaling for the DyanmoDB table.
* AutoScalingProps configuration to configure Read AutoScaling for the DynamoDB table.
* This field is optional and this can be achieved via addReadAutoScaling.
* @default undefined, read auto scaling is disabled
*/
readAutoScaling?: AutoScalingProps;

/**
* AutoScalingProps configuration to configure Write AutoScaling for the DyanmoDB table.
* AutoScalingProps configuration to configure Write AutoScaling for the DynamoDB table.
* This field is optional and this can be achieved via addWriteAutoScaling.
* @default undefined, write auto scaling is disabled
*/
Expand Down Expand Up @@ -111,7 +117,8 @@ export class Table extends Construct {
keySchema: this.keySchema,
attributeDefinitions: this.attributeDefinitions,
provisionedThroughput: { readCapacityUnits, writeCapacityUnits },
streamSpecification: props.streamSpecification ? {streamViewType: props.streamSpecification} : undefined
sseSpecification: props.sseEnabled ? { sseEnabled: props.sseEnabled } : undefined,
streamSpecification: props.streamSpecification ? { streamViewType: props.streamSpecification } : undefined
});

if (props.tableName) { this.addMetadata('aws:cdk:hasPhysicalName', props.tableName); }
Expand Down Expand Up @@ -293,4 +300,4 @@ export enum StreamViewType {
NewAndOldImages = 'NEW_AND_OLD_IMAGES',
/** Only the key attributes of the modified item are written to the stream. */
KeysOnly = 'KEYS_ONLY'
}
}
24 changes: 15 additions & 9 deletions packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.expected.json
Expand Up @@ -3,29 +3,35 @@
"TableCD117FA1": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"AttributeDefinitions": [
"KeySchema": [
{
"AttributeName": "hashKey",
"AttributeType": "S"
"KeyType": "HASH"
},
{
"AttributeName": "rangeKey",
"AttributeType": "N"
"KeyType": "RANGE"
}
],
"KeySchema": [
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
},
"AttributeDefinitions": [
{
"AttributeName": "hashKey",
"KeyType": "HASH"
"AttributeType": "S"
},
{
"AttributeName": "rangeKey",
"KeyType": "RANGE"
"AttributeType": "N"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
"SSESpecification": {
"SSEEnabled": true
},
"StreamSpecification": {
"StreamViewType": "KEYS_ONLY"
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts
@@ -1,11 +1,14 @@
import { App, Stack } from '@aws-cdk/cdk';
import { KeyAttributeType, Table } from '../lib';
import { KeyAttributeType, StreamViewType, Table } from '../lib';

const app = new App(process.argv);

const stack = new Stack(app, 'aws-cdk-dynamodb');

const table = new Table(stack, 'Table');
const table = new Table(stack, 'Table', {
sseEnabled: true,
streamSpecification: StreamViewType.KeysOnly
});

table.addPartitionKey('hashKey', KeyAttributeType.String);
table.addSortKey('rangeKey', KeyAttributeType.Number);
Expand Down
40 changes: 36 additions & 4 deletions packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts
Expand Up @@ -12,7 +12,7 @@ export = {
test.done();
},

'range key only'(test: Test) {
'hash key only'(test: Test) {
const app = new TestApp();
new Table(app.stack, 'MyTable').addPartitionKey('hashKey', KeyAttributeType.Binary);
const template = app.synthesizeTemplate();
Expand All @@ -33,7 +33,7 @@ export = {
test.done();
},

'range + hash key'(test: Test) {
'hash + range key'(test: Test) {
const app = new TestApp();
new Table(app.stack, 'MyTable').addPartitionKey('hashKey', KeyAttributeType.Binary)
.addSortKey('sortKey', KeyAttributeType.Number);
Expand All @@ -60,7 +60,35 @@ export = {

test.done();
},
'stream is not enabled by default'(test: Test) {
'server-side encryption is not enabled'(test: Test) {
const app = new TestApp();
new Table(app.stack, 'MyTable')
.addPartitionKey('partitionKey', KeyAttributeType.Binary)
.addSortKey('sortKey', KeyAttributeType.Number);
const template = app.synthesizeTemplate();

test.deepEqual(template, {
Resources: {
MyTable794EDED1: {
Type: 'AWS::DynamoDB::Table',
Properties: {
AttributeDefinitions: [
{ AttributeName: 'partitionKey', AttributeType: 'B' },
{ AttributeName: 'sortKey', AttributeType: 'N' }
],
KeySchema: [
{ AttributeName: 'partitionKey', KeyType: 'HASH' },
{ AttributeName: 'sortKey', KeyType: 'RANGE' }
],
ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 },
}
}
}
});

test.done();
},
'stream is not enabled'(test: Test) {
const app = new TestApp();
new Table(app.stack, 'MyTable')
.addPartitionKey('partitionKey', KeyAttributeType.Binary)
Expand Down Expand Up @@ -200,7 +228,9 @@ export = {
const table = new Table(app.stack, 'MyTable', {
tableName: 'MyTable',
readCapacity: 42,
writeCapacity: 1337
writeCapacity: 1337,
sseEnabled: true,
streamSpecification: StreamViewType.KeysOnly
});
table.addPartitionKey('partitionKey', KeyAttributeType.String);
table.addSortKey('sortKey', KeyAttributeType.Binary);
Expand All @@ -223,6 +253,8 @@ export = {
ReadCapacityUnits: 42,
WriteCapacityUnits: 1337
},
SSESpecification: { SSEEnabled: true },
StreamSpecification: { StreamViewType: 'KEYS_ONLY' },
TableName: 'MyTable',
}
}
Expand Down
27 changes: 27 additions & 0 deletions tools/pkglint/lib/rules.ts
Expand Up @@ -256,6 +256,33 @@ export class JSIIDotNetNamespaceIsRequired extends ValidationRule {
}
}

/**
* Strong-naming all .NET assemblies is required.
*/
export class JSIIDotNetStrongNameIsRequired extends ValidationRule {
public validate(pkg: PackageJson): void {
if (!isJSII(pkg)) { return; }

const signAssembly = deepGet(pkg.json, ['jsii', 'targets', 'dotnet', 'signAssembly']) as boolean | undefined;
const signAssemblyExpected = true;
if (signAssembly !== signAssemblyExpected) {
pkg.report({
message: `.NET packages must have strong-name signing enabled.`,
fix: () => deepSet(pkg.json, ['jsii', 'targets', 'dotnet', 'signAssembly'], signAssemblyExpected)
});
}

const assemblyOriginatorKeyFile = deepGet(pkg.json, ['jsii', 'targets', 'dotnet', 'assemblyOriginatorKeyFile']) as string | undefined;
const assemblyOriginatorKeyFileExpected = "../../key.snk";
if (assemblyOriginatorKeyFile !== assemblyOriginatorKeyFileExpected) {
pkg.report({
message: `.NET packages must use the strong name key fetched by fetch-dotnet-snk.sh`,
fix: () => deepSet(pkg.json, ['jsii', 'targets', 'dotnet', 'assemblyOriginatorKeyFile'], assemblyOriginatorKeyFileExpected)
});
}
}
}

/**
* The package must depend on cdk-build-tools
*/
Expand Down

0 comments on commit b6074ba

Please sign in to comment.