AWS CDK Java - Template format error: Mappings element count 0 should be greater than 0 - amazon-web-services

I would like to use AWS CDK with Java to create one simple VPC, with a public subnet, a security group and a EC2 instance. The Java class is the following, very simple:
public class CDKStack extends Stack {
public CDKStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CDKStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Create public subnet
SubnetConfiguration publicSubnet = SubnetConfiguration.builder()
.name("public-subnet")
.subnetType(SubnetType.PUBLIC)
.cidrMask(24)
.build();
List<SubnetConfiguration> subnetList = new ArrayList<>();
subnetList.add(publicSubnet);
// Create VPC with subnet above
Vpc vpc = new Vpc(this, "vpc-from-ckd", VpcProps.builder()
.cidr("10.0.0.0/16")
.maxAzs(1)
.subnetConfiguration(subnetList)
.build());
// Create the Security Group inside the VPC
SecurityGroup securityGroup = new SecurityGroup(this, "sg-cdk-java", SecurityGroupProps.builder()
.vpc(vpc)
.allowAllOutbound(true)
.build());
// Create image and EC2 instance
final GenericLinuxImage genericLinuxImage = new GenericLinuxImage(Collections.emptyMap());
Instance.Builder.create(this, "EC2 from CDK")
.instanceType(new InstanceType("t2.micro"))
.machineImage(genericLinuxImage)
.securityGroup(securityGroup)
.vpc(vpc)
.build();
}
}
Though, when I run cdk deploy (on Windows 10) I get the following error that I do not understand:
CDKStack: deploying...
CDKStack: creating CloudFormation changeset...
❌ CDKStack failed: Error [ValidationError]: Template format error: Mappings element count 0 should be greater than 0
Any help that could clarify what I'm doing wrong would be really appreciated, as I am going through samples and API documentation, but I cannot figure it out.

After some more search, I paid more attention to the error message and realized that Mappings refers to the Cloudformation Mappings (sounds obvious now that I think about it, but from the error message it is absolutely not clear, it seems more a verb in a sentence) and from their example in the official doc I thought it could be related to the environment variables.
So, I set them explicitly in the Java class and now it works:
.env(Environment.builder()
.account("1234567890")
.region("aws-region-name")
.build())

Related

AWS CDK - Connect a Network Load Balancer and a Neptune Cluster Endpoint together

For the past two days I've been struggling with exposing a Neptune endpoint to the public using an NLB in a single stack. The architecture was inspired by this document.
For the life of me I haven't been able to figure out how to obtain the IP address of the Neptune endpoint to use as the target of NLB's listener. The main issue resides in the conversion of the Neptune hostname to an IP address as required by NLB's target group IPTarget and how CDK synthesizes stacks before deployment.
I explored the use of CustomResources to no avail due to my limited familiarity with the topic (day 5 of my aws journey), and was hoping someone could point me in the right direction.
Here's my stack (CDK app repo here):
import { Construct } from "constructs";
import { Stack } from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
import * as neptune from "#aws-cdk/aws-neptune-alpha";
import { Props } from "../../_config";
import createVPC from "../helpers/createVPC";
import createNeptuneCluster from "../helpers/createNeptuneCluster";
import createNLB from "../helpers/createNLB";
export class ABCGraphStack extends Stack {
public readonly vpc: ec2.Vpc;
public readonly subnets: {
public: ec2.ISubnet[];
private: ec2.ISubnet[];
isolated: ec2.ISubnet[];
};
public readonly neptuneCluster: neptune.DatabaseCluster;
public readonly neptuneReadEndpoint: neptune.Endpoint;
public readonly neptuneWriteEndpoint: neptune.Endpoint;
public readonly nlb: elbv2.NetworkLoadBalancer;
constructor(scope: Construct, id: string, props: Props) {
super(scope, id, props);
// Create VPC for use with Neptune
const { vpc, subnets } = createVPC(props, this);
this.vpc = vpc;
this.subnets = subnets;
// Create Neptune Cluster
this.neptuneCluster = createNeptuneCluster(
props,
this,
this.vpc,
this.subnets
);
// Update Neptune Security Group to allow-all-in
this.neptuneCluster.connections.allowDefaultPortFromAnyIpv4(
"Allow All Inbound to Neptune"
);
// Add an ordering dependency on VPC.
this.neptuneCluster.node.addDependency(this.vpc);
// Output the Neptune read/write addresses
this.neptuneReadEndpoint = this.neptuneCluster.clusterReadEndpoint;
this.neptuneWriteEndpoint = this.neptuneCluster.clusterEndpoint;
// HOW TO GET IP ADDRESS OF this.neptuneWriteEndpoint.hostname?
// Create Network Load Balancer
this.nlb = createNLB(props, this, this.vpc, "????????", 8182);
this.nlb.node.addDependency(this.neptuneCluster);
}
}

How can you reference the primary network interface of an EC2 instance in AWS CDK?

In AWS-CDK I am trying to create a Traffic Mirroring Session. The EC2 machines are created in previous stacks and passed down as props to the new stack. However, while I am able to reference an ENI that was created explicitly (sniffing interface), I cannot find a way of referencing the EC2 primary network interface as the traffic mirror source
class TrafficMirringStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope,id,props)
const {
suricataInstance,
sniffingInterface,
targetInstance
} = props;
const mirrorTarget = new ec2.CfnTrafficMirrorTarget(this, 'TrafficMirrorTarget', {
description:' This is the traffic mirror target',
networkInterfaceId: sniffingInterface.ref,
});
const mirrorFilter = new ec2.CfnTrafficMirrorFilter(this, 'TrafficMirrorFilter', {
description: 'This filter allows all traffic from the target machine to be redirected to the sniffing interface',
networkServices:[],
});
const allowAllInboundRule = new ec2.CfnTrafficMirrorFilterRule(this, 'InboundMirrorFilter', {
destinationCidrBlock : '0.0.0.0/0',
sourceCidrBlock:'0.0.0.0/0',
trafficDirection: 'ingress',
ruleAction: 'accept',
ruleNumber:100,
trafficMirrorFilterId: mirrorFilter.ref
});
const allowAllOutboundRule = new ec2.CfnTrafficMirrorFilterRule(this, 'OutboundMirrorFilter', {
destinationCidrBlock : '0.0.0.0/0',
sourceCidrBlock:'0.0.0.0/0',
trafficDirection: 'egress',
ruleAction: 'accept',
ruleNumber:200,
trafficMirrorFilterId: mirrorFilter.ref
});
const mirrorSession = new ec2.CfnTrafficMirrorSession(this, 'TrafficMirrorSession', {
sessionNumber: 1,
networkInterfaceId: targetInstance.instance.networkInterfaceId,
trafficMirrorFilterId: mirrorFilter.ref,
trafficMirrorTargetId: mirrorTarget.ref
})
}
}
and I get the following error
Error: TrafficMirroringStack/TrafficMirrorSession [AWS::EC2::TrafficMirrorSession] is missing required property: networkInterfaceId
try to use:
instance.networkInterfaces
and find the interface you want.
see docs:
networkInterfaces - aws cdk doc

How do I access the NAT IP of a counted google_compute_instance in a connection block?

I'm trying to create multiple instances with count = number. During this I need to access IP address of created instance but I can't access attribute in loop. My version of Terraform is 0.12.26.
I've tried several approaches and nothing. Everything works until I try to access number of created instance via count.index. This is the code:
resource "google_compute_instance" "test" {
count = 2
name = "test-${count.index}"
# irrelevant stuff
connection {
host = google_compute_instance.test.*.network_interface.0.access_config.0.nat_ip[count.index]
# irrelevant stuff
I also tried advises from here with no luck:
How do I access an attribute from a counted resource within another resource?
According to those posts I've tried:
host = google_compute_instance.test[count.index].network_interface.0.access_config.0.nat_ip
host = element(google_compute_instance.test.*.network_interface.0.access_config.0.nat_ip, count.index)
Every time I get:
Error: Cycle: google_compute_instance.test[1], google_compute_instance.test[0]
How do I access the NAT IP of a counted google_compute_instance in a connection block?
Since you have an example of self-reference working for a single resource, this should work for the counted resources:
resource "google_compute_instance" "test" {
count = 2
name = "test-${count.index}"
# irrelevant stuff
connection {
host = self.network_interface.0.access_config.0.nat_ip
# irrelevant stuff
The self Object
Expressions in connection blocks cannot refer to their parent resource by name. Instead, they can use the special self object.
The self object represents the connection's parent resource, and has all of that resource's attributes. For example, use self.public_ip to reference an aws_instance's public_ip attribute.
The self Object from the Provisioner Connection Settings docs.

Can you create a route 53 A Record that maps directly to the IP address of a ecs service and ecs task defined using the AWS CDK?

Can you create a route 53 A Record that maps directly to the IP address of a ecs service and ecs task defined using the AWS CDK?
I have the following code
FargateTaskDefinition taskDef = new FargateTaskDefinition(this, "DevStackTaskDef", new FargateTaskDefinitionProps()
{
MemoryLimitMiB = 2048,
Cpu = 512
});
var service = new FargateService(this, "DevStackFargateService", new FargateServiceProps()
{
ServiceName = "DevStackFargateService",
TaskDefinition = taskDef,
Cluster = cluster,
DesiredCount = 1,
SecurityGroup = securityGroup,
AssignPublicIp = true,
VpcSubnets = new SubnetSelection()
{
SubnetType = SubnetType.PUBLIC
}
});
new ARecord(this, "AliasRecord", new ARecordProps()
{
Zone = zone,
Target = RecordTarget.FromIpAddresses() //here is the line in question.
});
The ARecordProps.Target value is the one I'm stuck on. I can not find a way to get the ip address of the task that will be created. Does any one know if this is possible to do? I would really like to avoid using load balancers as this is a dev/test environment. I have also looked at the aws-route53-targets module and see that it only supports
ApiGateway
ApiGatewayDomain
BucketWebsiteTarget
ClassicLoadBalancerTarget
CloudFrontTarget
LoadBalancerTarget
Any help would be much appreciated. Thanks

How to get security groups not yet assigned to an EC2 instance

I have the following method:
public String createGroup( String groupName, String description, String vpcId ) {
logger.debug( "Create Group called");
CreateSecurityGroupRequest sgrReq = new CreateSecurityGroupRequest();
sgrReq.setGroupName(groupName);
sgrReq.setDescription(description);
sgrReq.setVpcId(vpcId);
CreateSecurityGroupResult csgRes = ec2Client.createSecurityGroup(sgrReq );
String groupId = csgRes.getGroupId();
logger.debug( "Security Group '{}', with ID {}, created in VPC '{}'", groupName, groupId, vpcId);
return groupId;
}
It creates a security group, which I can see when I go the EC2 console for security groups. I have not yet assigned the group to an EC2 instance via ec2Client.modifyInstanceAttribute. What service/method of the AWS SDK would I use to list back all security groups, even those not yet assigned to any instances? To be explicit, ec2Client.getEc2Instance(ec2Id).getSecurityGroups() does not work, since the group has not yet been assigned to an instance.
You can use the DescribeSecurityGroups API without applying any filter.