Get EIP as output from aws-cdk generated VPC definition - aws-cloudformation

There is a vpc definition via
const vpc = new ec2.Vpc(this, 'SomeVPC', {
cidr: '10.0.0.0/16',
maxAzs: 2,
});
Under the hood it creates 2 EIP for NAT gateways
"SomeVPCPublicSubnet1EIP58E3D6C5": {
"Type": "AWS::EC2::EIP",
"Properties": {
"Domain": "vpc"
}
}
how to grab the references to them and export it via CfnOutput? Something like this:
new CfnOutput(this, "ExternalIPOutput", {value: <some magic call to get SomeVPCPublicSubnet1EIP58E3D6C5.ref()>})

It's been a while but I faced this issue today and this is how I managed to handle it and grab the EIP -
Code Snippet:
// Create new VPC
const vpc = new ec2.Vpc(this, 'VPC', {
cidr: props.customCidr,
maxAzs: 2,
subnetConfiguration: [
{
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE
},
{
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC
}
]
});
// Get Elastic IP
vpc.publicSubnets.forEach((subnet, index) => {
// Find the Elastic IP
const EIP = subnet.node.tryFindChild('EIP') as ec2.CfnEIP
new cdk.CfnOutput(this, `output-eip-${index}`, { value: EIP.ref });
})
Output:

Related

NextJS send data on redirect inside getServerSideProps

Is there a posibility to send data with redirect inside getServerSideProps function similar way as in next.config.js (you cannot pass hidden queries as far as I know inside next config file).
export const getServerSideProps = async (context) => {
const id = context.params.id;
return {
redirect: {
destination: '/my-work',
permanent: false,
has: [
{
type: 'query',
value: id
}
]
},
props: {
}
}
}
I want to pass hidden query to another page so this only works as middleware redirection as I am comming on this page from email template. But has object is not working in getServerSideProps function.
Is there any other ways to achieve that?
Thanks for your help!
This is from the official documentation.
module.exports = {
async redirects() {
return [
// if the header `x-redirect-me` is present,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'header',
key: 'x-redirect-me',
},
],
permanent: false,
destination: '/another-page',
},
// if the source, query, and cookie are matched,
// this redirect will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// destination since value is provided and doesn't
// use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
permanent: false,
destination: '/another/:path*',
},
// if the header `x-authorized` is present and
// contains a matching value, this redirect will be applied
{
source: '/',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
permanent: false,
destination: '/home?authorized=:authorized',
},
// if the host is `example.com`,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'host',
value: 'example.com',
},
],
permanent: false,
destination: '/another-page',
},
]
},
}
You can compare the params with it. For more details, visit here

Get IP address from Azure Private Endpoint using Pulumi TypeScript API

I have a Private Endpoint created in my Azure subscription. If I look into the Azure Portal I can see that the private IP assigned to my Private Endpoint NIC is 10.0.0.4.
But how can I get the IP address value using the Pulumi TypeScript API, so I can use it in my scripts?
const privateEndpoint = new network.PrivateEndpoint("privateEndpoint", {
privateLinkServiceConnections: [{
groupIds: ["sites"],
name: "privateEndpointLink1",
privateLinkServiceId: backendApp.id,
}],
resourceGroupName: resourceGroup.name,
subnet: {
id: subnet.id,
}
});
export let ipc = privateEndpoint.networkInterfaces.apply(networkInterfaces => networkInterfaces[0].ipConfigurations)
console.log(ipc)
This is the current output for that ipc variable:
OutputImpl {
__pulumiOutput: true,
resources: [Function (anonymous)],
allResources: [Function (anonymous)],
isKnown: Promise { <pending> },
isSecret: Promise { <pending> },
promise: [Function (anonymous)],
toString: [Function (anonymous)],
toJSON: [Function (anonymous)]
}
You can't log a pulumi Output until its resolved, so if you change your code slightly, this will work:
const privateEndpoint = new network.PrivateEndpoint("privateEndpoint", {
privateLinkServiceConnections: [{
groupIds: ["sites"],
name: "privateEndpointLink1",
privateLinkServiceId: backendApp.id,
}],
resourceGroupName: resourceGroup.name,
subnet: {
id: subnet.id,
}
});
export let ipc = privateEndpoint.networkInterfaces.apply(networkInterfaces => console.log(networkInterfaces[0].ipConfigurations))
I found the solution to my problem.
I was publishing a Static Web App to an incorrect Private DNS Zone. Correct one should be privatelink.1.azurestaticapps.net.
Once that was fixed I got the data that I needed.
{
name: 'config1',
privateDnsZoneId: '/subscriptions/<subscription>/resourceGroups/rg-static-webappc0811aae/providers/Microsoft.Network/privateDnsZones/privatelink.1.azurestaticapps.net',
recordSets: [
{
fqdn: 'thankful-sand-084c7860f.privatelink.1.azurestaticapps.net',
ipAddresses: [Array],
provisioningState: 'Succeeded',
recordSetName: 'thankful-sand-084c7860f',
recordType: 'A',
ttl: 10
}
]
}
{
fqdn: 'thankful-sand-084c7860f.privatelink.1.azurestaticapps.net',
ipAddresses: [ '10.0.0.4' ],
provisioningState: 'Succeeded',
recordSetName: 'thankful-sand-084c7860f',
recordType: 'A',
ttl: 10
}

Merge or 'reference' and object into another through GraphQL?

Very new to graphQL (and MongoDB), and I am wondering how to reference an another object in graph QL.
I have two objects in two collections in MongoDB...
{
_id: 1,
companies: [
{
id: 1,
name: 'Google'
},
{
id: 2,
name: 'Apple'
}
]
}
{
_id: 2,
jobs: [
{
id: 1,
title: 'Designer'
},
{
id: 2,
name: 'Developer'
}
]
}
The Designer job is posted by google, and I want to include that in the returned object from GraphQL (I am using the 'id: 1' as a reference I guess? Presume ObjectID might be the way to go instead tho )
How would I go about that?
Ideally I want to return
{
"data": {
"job": {
"id": 1,
"title": "Designer",
"company": {
id: 1,
name: "Google"
}
}
}
}
But not sure how to go about it, I currently have...
resolvers.js
export const resolvers = {
Query: {
jobs: async (_parent, {}, context) => {
const jobs = await context.db
.collection('jobs')
.findOne()
return jobs.jobs
},
companies: async (_parent, {}, context) => {
const companies = await context.db
.collection('companies')
.findOne()
return companies.companies
},
job: async (_parent, { id }, context) => {
const job = await context.db.collection('jobs').findOne()
return job.jobs.find((job) => job.id === Number(id))
},
},
}
typeDefs.js
export const typeDefs = gql`
type Job {
_id: ID
id: Int
title: String
}
type Company {
_id: ID
id: Int
name: String
}
type Query {
jobs: [Job]
companies: [Company]
job(id: Int): Job
}
`
But not sure how to tie these in together? I am using Apollo / GraphQL / MongoDB / NextJS and essentially set up very close to this
Thanks in advance for any help or guidance!

How to get the ARN of a codepipeline inside of the same CDK stack

I am trying to set up a notification rule as part of a code pipeline in a CDK stack.
Note this is NOT a CDK pipeline but a CDK stack that is setting up a AWS CodePipeline.
In order to create a CfnNotificationRule I must pass in the ARN of the CodePipeline as the resource parameter. In the sample code below I've hardcoded the ARN as TARGET_ARN
However, I would like to provide this dynamically.
How do I provide the ARN that CDK generates for my-pipeline to the CfnNotificationRule constructor?
const codepipeline = require('#aws-cdk/aws-codepipeline');
class PipelineStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
//I want the ARN of this pipeline in TARGET_ARN
new codepipeline.Pipeline(this, 'Pipeline', {
crossAccountKeys: false,
pipelineName: "my-pipeline",
stages: [{
stageName: 'Source',
},
{
stageName: 'Build',
},
{
stageName: 'Deploy',
]
}
]
})
const AWS_SLACK_CHATBOT_ARN = 'arn:aws:chatbot::111111111111:chat-configuration/slack-channel/my-slack-channel'
const TARGET_ARN = 'arn:aws:codepipeline:us-east-2:111111111111:my-pipeline'
const notes = new notifications.CfnNotificationRule(this, 'my-dev-slack', {
detailType: "FULL",
name: "my-dev-slack",
eventTypeIds: [
"codepipeline-pipeline-action-execution-succeeded",
"codepipeline-pipeline-action-execution-failed",
"codepipeline-pipeline-stage-execution-failed"
],
targets: [{
targetType: "AWSChatbotSlack",
targetAddress: AWS_SLACK_CHATBOT_ARN
}],
resource: TARGET_ARN
})
}
}
Initialise the pipeline as a local variable and then you can use its internal methods after, for example your new code would look like this (I noticed you had a bracket [ under stageName: 'Deploy', which was causing the code note to compile so I have removed it in my example )
const myPipeline = new codepipeline.Pipeline(this, 'Pipeline', {
crossAccountKeys: false,
pipelineName: "my-pipeline",
stages: [{
stageName: 'Source',
},
{
stageName: 'Build',
},
{
stageName: 'Deploy',
}]
})
myPipeline.pipelineArn
myPipeline.pipelineArn will give you the ARN

Setting up AWS IoT using Serverless Framework for Multiple IoT Devices

My goal is to create a system on AWS using the serverless framework for multiple IoT devices to send JSON payloads to AWS IoT, which in turn will be saved to DynamoDB.
I am very new to using AWS outside of creating EC2 servers and this is my first project using the serverless framework.
After referring to an example, the modified version that I came up with is posted below.
Problem: It appears that the example is for just 1 device to connect to AWS IoT, which I concluded from the hardcoded IoT Thing certificate being used, such as
SensorPolicyPrincipalAttachmentCert:
Type: AWS::IoT::PolicyPrincipalAttachment
Properties:
PolicyName: { Ref: SensorThingPolicy }
Principal: ${{custom.iotCertificateArn}}
SensorThingPrincipalAttachmentCert:
Type: "AWS::IoT::ThingPrincipalAttachment"
Properties:
ThingName: { Ref: SensorThing }
Principal: ${self:custom.iotCertificateArn}
If this conclusion is correct that serverless.yml is configured for only 1 Thing, then what modifications can we make such that more than 1 Thing can be used?
Maybe setup all the Things outside of serverless.yaml? Which means removing just SensorPolicyPrincipalAttachmentCert and SensorThingPrincipalAttachmentCert?
Also, how should we set the Resource property to in SensorThingPolicy? They are currently set to "*", is this too broard? Or is there a way to limit to just Things.
serverless.yml
service: garden-iot
provider:
name: aws
runtime: nodejs6.10
region: us-east-1
# load custom variables from a file
custom: ${file(./vars-dev.yml)}
resources:
Resources:
LocationData:
Type: AWS::DynamoDB::Table
Properties:
TableName: location-data-${opt:stage}
AttributeDefinitions:
-
AttributeName: ClientId
AttributeType: S
-
AttributeName: Timestamp
AttributeType: S
KeySchema:
-
AttributeName: ClientId
KeyType: HASH
-
AttributeName: Timestamp
KeyType: RANGE
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
SensorThing:
Type: AWS::IoT::Thing
Properties:
AttributePayload:
Attributes:
SensorType: soil
SensorThingPolicy:
Type: AWS::IoT::Policy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: ["iot:Connect"]
Resource: ["${self:custom.sensorThingClientResource}"]
- Effect: "Allow"
Action: ["iot:Publish"]
Resource: ["${self:custom.sensorThingSoilTopicResource}"]
SensorPolicyPrincipalAttachmentCert:
Type: AWS::IoT::PolicyPrincipalAttachment
Properties:
PolicyName: { Ref: SensorThingPolicy }
Principal: ${{custom.iotCertificateArn}}
SensorThingPrincipalAttachmentCert:
Type: "AWS::IoT::ThingPrincipalAttachment"
Properties:
ThingName: { Ref: SensorThing }
Principal: ${self:custom.iotCertificateArn}
IoTRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Principal:
Service:
- iot.amazonaws.com
Action:
- sts:AssumeRole
IoTRolePolicies:
Type: AWS::IAM::Policy
Properties:
PolicyName: IoTRole_Policy
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- dynamodb:PutItem
Resource: "*"
-
Effect: Allow
Action:
- lambda:InvokeFunction
Resource: "*"
Roles: [{ Ref: IoTRole }]
EDIT 05/09/2018: I've found this blog post, which describes my approach pretty well: Ensure Secure Communication with AWS IoT Core Using the Certificate Vending Machine Reference Application
--
You could take a look at Just-in-Time Provisioning or build your own solution based on Programmatic Provisioning.
I have dealt with this topic many times and had to realize that it depends a lot on the use case, which makes more sense. Also security is an aspect to keep an eye on. You don't want to have a public API responsible for JIT device registration accessible by the whole Internet.
A simple Programmatic Provisioning-based scenario could look like this: You build a thing (maybe a sensor), which should be abled to connect to AWS IoT and have an in-house provisioning process.
Simple provisioning process:
Thing built
Thing has a serial number
Thing registers itself via an internal server
The registration code running on the server could look something like this (JS + AWS JS SDK):
// Modules
const AWS = require('aws-sdk')
// AWS
const iot = new AWS.Iot({ region: process.env.region })
// Config
const templateBodyJson = require('./register-thing-template-body.json')
// registerThing
const registerThing = async ({ serialNumber = null } = {}) => {
if (!serialNumber) throw new Error('`serialNumber` required!')
const {
certificateArn = null,
certificateId = null,
certificatePem = null,
keyPair: {
PrivateKey: privateKey = null,
PublicKey: publicKey = null
} = {}
} = await iot.createKeysAndCertificate({ setAsActive: true }).promise()
const registerThingParams = {
templateBody: JSON.stringify(templateBodyJson),
parameters: {
ThingName: serialNumber,
SerialNumber: serialNumber,
CertificateId: certificateId
}
}
const { resourceArns = null } = await iot.registerThing(registerThingParams).promise()
return {
certificateArn,
certificateId,
certificatePem,
privateKey,
publicKey,
resourceArns
}
}
const unregisterThing = async ({ serialNumber = null } = {}) => {
if (!serialNumber) throw new Error('`serialNumber` required!')
try {
const thingName = serialNumber
const { principals: thingPrincipals } = await iot.listThingPrincipals({ thingName }).promise()
const certificates = thingPrincipals.map((tp) => ({ certificateId: tp.split('/').pop(), certificateArn: tp }))
for (const { certificateId, certificateArn } of certificates) {
await iot.detachThingPrincipal({ thingName, principal: certificateArn }).promise()
await iot.updateCertificate({ certificateId, newStatus: 'INACTIVE' }).promise()
await iot.deleteCertificate({ certificateId, forceDelete: true }).promise()
}
await iot.deleteThing({ thingName }).promise()
return {
deleted: true,
thingPrincipals
}
} catch (err) {
// Already deleted!
if (err.code && err.code === 'ResourceNotFoundException') {
return {
deleted: true,
thingPrincipals: []
}
}
throw err
}
}
register-thing-template-body.json:
{
"Parameters": {
"ThingName": {
"Type": "String"
},
"SerialNumber": {
"Type": "String"
},
"CertificateId": {
"Type": "String"
}
},
"Resources": {
"thing": {
"Type": "AWS::IoT::Thing",
"Properties": {
"ThingName": {
"Ref": "ThingName"
},
"AttributePayload": {
"serialNumber": {
"Ref": "SerialNumber"
}
},
"ThingTypeName": "NewDevice",
"ThingGroups": ["NewDevices"]
}
},
"certificate": {
"Type": "AWS::IoT::Certificate",
"Properties": {
"CertificateId": {
"Ref": "CertificateId"
}
}
},
"policy": {
"Type": "AWS::IoT::Policy",
"Properties": {
"PolicyName": "DefaultNewDevicePolicy"
}
}
}
}
Make sure you got all the "NewDevice" Thing types, groups and policies in place. Also keep in mind ThingName = SerialNumber (important for unregisterThing).