How to use CDK to get the IP addresses of the enis associated with a VPCE/ how to get the vpceNetworkInterfaceIds associated with a VPCE? - aws-sdk

Background context / End goal:
I am trying to use cdk to create a target group that consists of the ip addresses that are associated with a vpc endpoint (for apigateway) as per this AWS blog.
Ideally, I would like to be able to just lookup the associated ips using just the fact that the vpce is for the service of apigateway OR potentially using the vpce id.
Attempts
I tried to use the cdk InterfaceVpcEndpoint construct static method using the fromInterfaceVpcEndpointAttributes (filtering by service). It did return the desired vpce, but unfortunately it returns in the format of IInterfaceVpcEndpoint which does not have the vpceNetworkInterfaceIds attribute that the InterfaceVpcEndpoint construct has
I was able to use AwsCustomResource (after consulting a stack overflow post that referenced this example) to look up the ip addresses for a given array of vpce network interface ids:
const vpceNetworkInterfaceIds = =['eniId1', 'eniId2'];
const getEniIps = new AwsCustomResource(scope, `GetEndpointIps`, {
onUpdate: {
service: "EC2",
action: "describeNetworkInterfaces",
parameters: {
NetworkInterfaceIds: vpceNetworkInterfaceIds
},
physicalResourceId: PhysicalResourceId.of(Date.now().toString())
},
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE
}),
});
const privateIpAddresses: string[] = [];
for(let i = 0; i< vpceNetworkInterfaceIds.length; i++){
const privateIpAddress: string = getNetworkInterfaceIpAddresses.getResponseField(`NetworkInterfaces.${i}.PrivateIpAddress`).toString();
privateIpAddresses.push(privateIpAddress);
}
return privateIpAddresses;
}
I tried to make a similar sdk call (describeVpcEndpoints), but then I encountered issues retrieving the array of NetworkInterfaceIds.
const getNetworkInterfaceIpAddresses = new AwsCustomResource(scope, `GetVpceNetworkInterfaceIds`, {
onUpdate: {
service: "EC2",
action: "describeVpcEndpoints",
parameters: {
Filters: [
{
Name: "service-name",
Values: ["com.amazonaws.us-east-1.execute-api"]
}
]
},
physicalResourceId: PhysicalResourceId.of(Date.now().toString())
},
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE
}),
});
return getNetworkInterfaceIpAddresses.getResponseFieldReference(`VpcEndpoints.0.NetworkInterfaceIds`).toJSON();
I tried variations of using the Reference methods of toJson and toString but was not able to figure out how to get the array of values from this custom resource.
Questions
How can you get an array from the sdk call of a aws custom resource?
Is there a more straight forward way to get the vpceNetworkInterfaceIds of a given vpce?
Is there a more straight forward way to get the ip addresses for a given vpce?

Related

web3.eth.accounts.create method doesn't actually create new account

I try to create an eth account via RPC in private network.
What I have done so far are:
launch geth node and create private network.
create simple javascript program using web3 1.0.0, typescript
run and get result as below but the account isn't created
Code:
const result = await web3.eth.personal.unlockAccount(senderId, senderPassword, duration)
if (result === true) {
// const newAccountResult = await web3.eth.personal.newAccount('password')
const newAccountResult = await web3.eth.accounts.create('user01')
console.log(newAccountResult)
}
Result:
web3.eth.accounts.create returns the following result
{ address: '0xf10105f862C1cB10550F4EeB38697308c7A290Fc',
privateKey: '0x5cba6b397fc8a96d006988388553ec17a000f7da9783d906979a2e1c482e7fcb',
signTransaction: [Function: signTransaction],
sign: [Function: sign],
encrypt: [Function: encrypt] }
But web3.eth.getAccounts method returns only 1 account.
[ '0xaf0034c41928Db81E570061c58c249f61CFF57f2' ]
Seems web3.eth.accounts.create method has succeeded as the result includes account address and private key.
But I don't understand why web3.eth.getAccounts method doesn't include the created account.
I also checked geth via console, the result is same.
> eth.accounts
["0xaf0034c41928db81e570061c58c249f61cff57f2"]
And eth.personal.newAccount didn't work.
Do I need to do something after web3.eth.accounts.create?
I appreciate any help.
If i got it right, web.eth.accounts.create is a way to create accounts without storing them on the local node, so its basically a way to get a valid keypair on-the-fly without storing anything on the keystore)
web3.eth.personal.newAccount() should be availabel if you have the personal-API activated on your geth node (which is default behavior for ganache, with geth you need to activate it via geth --dev/testnet --rpc --rpcapi eth,web3,personal (note: of course you should be very careful with allowing personal-API on mainnet, make sure that RPC access is restricted so only you/privileged users can access it)
(async () => {
let newAccount = await web3.eth.personal.newAccount();
console.log(newAccount);
let accounts = await web3.eth.getAccounts();
console.log(accounts);
})();
Should give something like
0xb71DCf0191E2B90efCD2638781DE40797895De66
[
...
'0xb71DCf0191E2B90efCD2638781DE40797895De66' ]
Refs https://medium.com/#andthentherewere0/should-i-use-web3-eth-accounts-or-web3-eth-personal-for-account-creation-15eded74d0eb

How to add array values in Claims of IdToken in Cognito using claimsToAddOrOverride

I am using Pre Token Generation to update the claims of IdToken.
I am successfully able to update claim using single key:value pair.
Below is the sample example of that.
event["response"] = {"claimsOverrideDetails":{"claimsToAddOrOverride":{"scope": "test.debug"}}}
But when i am trying to add array of string inside that, it giving me internal server error (Response from AWS Cognito)
Ex:
event["response"] = {"claimsOverrideDetails":{"claimsToAddOrOverride":{"scope": ["test1","test2]}}}
It is working fine using 'Test' option of lambda function.
If i am using groupsToOverride then it is overriding the cognito:groups claim.
Any help?
I think this must be a bug with Cognito and unfortunately will require a workaround until it's resolved.
It's not ideal I know, but I've worked around this issue by using a delimited string which I then parse to an array when I receive the token.
Lambda:
exports.handler = (event, context, callback) => {
event.response = {
"claimsOverrideDetails": {
"claimsToAddOrOverride": {
"scope": "test1|test2"
}
}
};
// Return to Amazon Cognito
callback(null, event);
};
Client:
const token = jwt.decode(id_token);
const scopes = token.scope.split('|');
The name scope have special meaning in a JWT, libraries expect this to be a list in string form separated by space. So the scopes test1 and test2 would become "test1 test2".
I would recommend using space as separator and not any other format. If you prefer another format just give your field a different name - like group.
{
"iss": "https://authorization-server.example.com/",
"sub": " 5ba552d67",
"aud": "https://rs.example.com/",
"exp": 1544645174,
"client_id": "s6BhdRkqt3_",
"scope": "openid profile reademail"
}

How to replace sagas during run time?

I have a React Native app that may connect to different API endpoints. Some users may need to change API endpoint on the run time, without restarting the app. All the API requests are bound to sagas, and the root saga looks like
export default function* rootSaga() {
yield [
takeLatest([
ONE_REQUEST,
ANOTHER_REQUEST,
// a bunch of sagas that are responsible for API querying
], api); // <- here, api is global.
];
}
so it can run along with the newly instantiated Redux store:
import rootSaga from './sagas';
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
// other stuff, and finally
sagaMiddleware.run(rootSaga).done.catch(console.error);
The problem is, once executed, the Store, let alone sagas, can never be updated.
I tried to pass api to root saga as the first argument:
export default function* rootSaga(baseUrl = DEFAULT_API_URL) {
const api = create({
baseUrl,
// other stuff that is required by apisauce
});
yield [
takeLatest([
ONE_REQUEST,
ANOTHER_REQUEST,
// a bunch of sagas that are responsible for API querying
], api); // <- here, api is instantiated per every yield* of rootSaga.
];
}
I tried to refer to the generator itself from within a function executed per a certain action type:
yield [
takeLatest([
ONE_REQUEST,
ANOTHER_REQUEST,
// a bunch of sagas that are responsible for API querying
], api); // <- here, api is instantiated per every yield* of rootSaga.
takeEvery([
REPLACE_API // <- the action I would dispatch to replace API endpoint
], ({endpoint}) => {
yield cancel(rootSaga);
yield* rootSaga(endpoint); // <- the new API endpoint
});
];
But it didn't work. I also tried a bunch of other tactics, but none really worked either. And I looked up the docs for something similar to Redux's replaceReducer, but there's nothing like this for redux-saga, which makes me feel that it can be done using only proper sequence yielded by root saga generator.
So, is there a general approach to this problem? Is it possible to re-instantiate root saga on the run time?
It seems that you can add the endpoint URL to the state tree and manage updating the URL based on a typical redux-saga flow. Then, when you dispatch your REQUEST actions, just read the current end point URL from the state tree and attach that as a payload to the REQUEST action. Then, in your api saga, use that URL payload.

Why can I not access 'passport' fields in session store JSON?

I've got a node application that uses express, socket.io 1.0 and passport. When a user auths through passport-twitter I store their information in a session store using the below code;
var passportSocketIo = require("passport.socketio");
var MemoryStore = express.session.MemoryStore
,sessionStore = new MemoryStore();
io.set('authorization', passportSocketIo.authorize({
cookieParser: express.cookieParser,
key: 'express.sid',
secret: 'secret',
store: sessionStore
}));
I then use the following for my socket.io connection handler;
io.on("connection", function(client){
console.log(sessionStore.sessions[client.request.sessionID]);
});
This returns all the session data for the client with that ID in this format;
{
"cookie": {
"originalMaxAge": null,
"expires": null,
"httpOnly": true,
"path": "/"
},
"passport": {
"user": {
"id": "XXXXXXXXXX",
[...],
[...]
}
}
}
The issue is that if I tried to access "passport" from the structure, the result is always undefined. I tried the following (both with and without the . before "passport");
sessionStore.sessions[client.request.sessionID].[passport]
sessionStore.sessions[client.request.sessionID].["passport"]
sessionStore.sessions[client.request.sessionID].passport
sessionStore.sessions[client.request.sessionID]."passport"
Unfortunately these return as undefined. I'm really just trying to get the passport.user.id field value out of that structure so I can perform some DB lookup (e.g. user group, user privacy settings, etc) and so I can ensure I emit the correct DB data back to the client.
Any ideas?
After looking into it further, it appears that passing it through JSON.parse() was the correct method to use;
var jsobj = JSON.parse(sessionStore.sessions[client.request.sessionID]);
console.log(jsobj.passport.user.id);
or for a single line solution;
console.log(JSON.parse(sessionStore.sessions[client.request.sessionID]).passport.user.id);

Sending complex JSON with fetch, save, and delete on a model or collection

We have an internal API that was specifically built to be used with a new piece of software I'm building that runs on Backbone. The API has a single URL and takes JSON as input to determine what it needs to return. It essentially allows me to build custom queries with JSON that return exactly what I'm looking for.
Thing is this JSON can get pretty verbose and is often 3–4 levels deep, but sometimes may just be a few lines and just 1 level deep.
First question first: How do I send a string of JSON along with the ID when I do a fetch()? Do I have to set these parameters as the model or collection's defaults?
Here is an example of a really simple string to get a specific user's info
{
"which" : "object",
"object" : {
"type" : "customer",
"place" : "store",
"customerID" : "14"
}
}
As others have suggested it will likely be challenging to work with SOAP, but it shouldn't be impossible. Backbone models and collections communicate with the server through the sync operation; you should be able to customize that. I think something along these lines might get the ball rolling (for models):
Backbone.SoapyModel = Backbone.Model.extend({
sync: function(method, model, options) {
// force POST for all SOAP calls
method = 'create';
options = _.extend(options, {
// Setting the data property will send the model's state
// to the server. Add whatever complexity is needed here:
data: JSON.stringify({
"which" : "object",
"object" : model.toJSON()
}),
// Set the request's content type
contentType: 'application/json'
});
// Defer the rest to Backbone
return Backbone.sync.apply(this, [method, model, options]);
}
});
var SoapyModelImpl = Backbone.SoapyModel.extend({
url: '/test'
});
var soapTest = new SoapyModelImpl({
id: 42,
name: 'bob',
address: '12345 W Street Dr',
phone: '867 5304'
});
soapTest.fetch();