Canary - AccessDeniedException: Access to KMS is not allowed - amazon-cloudwatch

I have setup a simple synthetic transaction monitoring (canary) in aws, that running a POST HTTP request, against specific endpoint, using a secret keys defined in AWS Secretes Manager (ASM).
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
const getKeyCert = async () => {
var params = {
SecretId: "arn:aws:secretsmanager:us-west-1:443682978425:secret:Canary_BO_TLS_CER-LalJXG"
};
const key = await secretsManager.getSecretValue(params).promise();
var params = {
SecretId: "arn:aws:secretsmanager:us-west-1:443682978425:secret:Canary_BO_TLS_CER-LalJXG"
};
const cert = await secretsManager.getSecretValue(params).promise();
}
var synthetics = require('Synthetics');
const log = require('SyntheticsLogger');
const syntheticsConfiguration = synthetics.getConfiguration();
const apiCanaryBlueprint = async function () {
const [ key, cert ] = await getKeyCert();
syntheticsConfiguration.setConfig({
restrictedHeaders: [], // Value of these headers will be redacted from logs and reports
restrictedUrlParameters: [] // Values of these url parameters will be redacted from logs and reports
});
I have also attached the GetSecretValue policy, in the IAM. to the role that running the Canary.
But from some reason, i'm getting an error message that related to Key Management Service (KMS):
AccessDeniedException: Access to KMS is not allowed Stack: AccessDeniedException: Access to KMS is not allowed
Which is very interesting,
Because i did not encrypt the my secret in the AWS Secrets Manager (ASM).
which led me think, that maybe that could it be that Key Management Service (KMS) is encrypting secrets by default, if i didn't encrypt them from the first place?
I'm not sure how to solve this issue.

verify if secrets manager key is defined with "Encryption key"

Related

Generate signed URL for R2 from Cloudflare worker

I am trying to replicate the result from this guide: https://developers.cloudflare.com/r2/data-access/s3-api/presigned-urls/
However, with the exact same code, the signedUrl variable return empty object({}).
If anyone has any insight would be much appreciated!
According to my understanding and as written in the docs, I don't have to pass any accessKeyId or secretAccessKey.
However, the s3 url that I got from my cloudflare dashboard is : https://<ACCOUNT ID>.r2.cloudflarestorage.com/<DROPBOX BUCKET>, which is different from the docs.
const r2 = new AwsClient({
accessKeyId: "",
secretAccessKey: "",
service: "s3",
region: "auto",
});
app.get("/getUploadUrl", async (c) => {
const timeOut = +c.req.queries("timeOut") ?? 60 * 5;
const fileName = c.req.queries("fileName") ?? crypto.randomUUID();
const bucketName = c.req.header("bucket");
const bucketUrl = bucketNameToUrl[bucketName];
console.log("fileName", fileName);
const signedUrl = await r2.sign(
new Request(`${bucketUrl}/${fileName}`, {
method: "PUT",
}),
{
aws: { signQuery: true },
headers: {
"X-Amz-Expires": timeOut.toString(),
},
}
);
return c.json(signedUrl);
});
You can also use the URL format:
https://<bucket_name>.<account_id>.r2.cloudflarestorage.com
both the slash at the end and this version should work.
The Access Key and Secret Access Key need to be generated with the button on the right of the R2 console labelled "R2 API Keys". There's also a Discord server where you can get help and learn a lot about R2, and Cloudflare in general

Does anyone know how to apply dependencies on cloudflare worker?

I was trying to create a free service using cloudflare but i need to use googleapis and nodemailer. So I need to add the dependencies.
Here is an example of how to access Google Cloud APIs from under a Cloudfalre Worker script. You would just need to create a Google Cloud service account (IAM) with required permissions and a JSON private key for it.
import { getAuthToken } from "web-auth-library/google";
export default {
fetch(req, env) {
cosnt accessToken = await getAuthToken({
credentials: env.GOOGLE_CLOUD_CREDENTIALS,
// TODO: List the required GCP scopes here
scope: "https://www.googleapis.com/auth/cloud-platform",
});
// Access any of the Google Cloud REST APIs using that token
const url = `https://cloudresourcemanager.googleapis.com/v1/projects`;
const headers = new Headers({ authorization: `Bearer ${accessToken}` });
const res = await fetch(url, { headers });
const data = await res.json();
// ...
}
}
References
https://github.com/kriasoft/web-auth-library — OAuth 2.0 library for Cloudflare Workers
https://github.com/kriasoft/cloudflare-starter-kit — Cloudflare Workers Starter Kit

OctoKit with Auth0 (Github Login) in NextJS

I am building a Next JS app that has Github Login through Auth0 and uses the Octokit to fetch user info / repos.
In order to get the IDP I had to setup a management api in auth0. https://community.auth0.com/t/can-i-get-the-github-access-token/47237 which I have setup in my NodeJs server to hide the management api token as : GET /getaccesstoken endpoint
On the client side : /chooserepo page, I have the following code :
const chooserepo = (props) => {
const octokit = new Octokit({
auth: props.accessToken,
});
async function run() {
const res = await octokit.request("GET /user");
console.log("authenticated as ", res.data);
}
run();
And
export const getServerSideProps = withPageAuthRequired({
async getServerSideProps({ req, params }) {
let { user } = getSession(req);
console.log("user from get session ", user);
let url = "http://localhost:4000/getaccesstoken/" + user.sub;
let data = await fetch(url);
let resData = await data.text();
return {
props: { accessToken: resData }, // will be passed to the page component as props
};
},
});
However, I keep getting Bad credentials error. If I directly put the access token in the Octokit it seems to work well, but doesn't work when it's fetching the access token from the server.
It seems like Octokit instance is created before server side props are sent. How do I fix it ?
I figured out the error by comparing the difference between the request headers when hardcoding and fetching access token from server. Turns out quotes and backslashes need to be replaced (and aren't visible when just console logging)

Store Socket IO socket.id in Express session

I have a web app using Angular and Express. I have a rest api for database updates and I am also using SocketIO to update the clients in realtime.
I am tracking a list of active socket IDs for each user but now I would like to have access to the clients socket id in my express route so that I can emit a message to all other users (equivalent of socket.broadcast)
I'm trying to store the socket ID in an expression session so I can access it in my route but i've not been able to get it working. In the code below i'm logging my session when the socket connects and this shows the socketio key i've added but in the /jobs request the socketio key is undefined..
My server.ts is something like this:
import * as expsession from 'express-session'
// create Express app variable
const app = express()
// create HTTP server
const server = http.createServer(app);
// set up CORS so it can work Angular application at another domain/port
app.use(cors({
origin: [ "http://localhost:4200" ],
credentials: true
}))
// install session middleware
const session = expsession({
secret: 'random secret',
saveUninitialized: true,
resave: true,
cookie: { secure: false }
});
// run session middleware for regular http connections
app.use(session);
// *** SOCKET IO *** //
const io = require('socket.io')(server);
// run session middleware for socket.io connections
io.use((socket, next) => {
session(socket.request, socket.request.res || {}, next);
});
// when a socket.io connection connects, put the socket.id into the session
// so it can be accessed from other http requests from that client
io.on('connection', (socket) => {
console.log(`socket.io connected: ${socket.id}`);
// save socket.io socket in the session
socket.request.session.socketio = socket.id;
socket.request.session.save();
console.log("socket.io connection, session:\n", socket.request.session);
});
app.get('/jobs', (req, res) => {
const session = req.session;
console.log("JOBS: session at '/jobs':\n", session);
Job.getJobs((err, jobs) => {
if (err) {
res.json({success: false, msg: err});
} else {
res.json(jobs);
}
});
});
I'm also including credentials in my angular service request, e.g.:
this.http.get(api_url + '/jobs', {withCredentials:true}).subscribe((jobs:IJob[]) => {
this.jobs$.next(jobs)
})
When a socket is connected an id is created(socket.id) and by default it joins to a room with that id. If you already have id for your client just send it to the server and join to a room with the client id.
socket.leave(socket.id);//leaving default room
socket.join(my_custom_id);//joining to custom id room
the custom id will appear in client side as the websocket7 id.
If you still don't know how to get the id in your express route; use a jsonwebtoken with the id and decoded in your route, thats it.
Example:
var bearer = req.headers.authorization.split(" ")[1];//this is node, get headers with express way
var auth_data = jwt.decodeToken( bearer );
decoding:
var jwt = require('jsonwebtoken');
var secret = 'your_secret';
function decodeToken(token){
try {
var decoded = jwt.verify( token , secret );
return decoded;
} catch (error) {
console.log('jwt', error);
return null;
}
}
encoding:
//data is an object with data you want to encode, id, etc
function createJsonWebToken(data){
var token = jwt.sign( data, secret );
return token
}
/*after encoding you send this token to the
client, then you send it back to the server
to the routes you need the data, then just
decoded it in that route*/

How use the #c8y/client library

I am testing the new #c8y/client library for typescript.
I have a very simple code :
import {
Client
} from '#c8y/client';
//const baseUrl = 'https://bismark1.cumulocity.com/';
const baseUrl = 'https://demos.cumulocity.com/';
const tenant = 'bismark1';
const user = '...';
const password = '.....';
(async() => {
console.log('authentication to c8y server')
const client = await Client.authenticate({
user,
password,
tenant
}, baseUrl);
console.log('result from authetication', client)
const {
data,
paging
} = await client.inventory.list();
console.log('result from inventory ', data)
// data = first page of inventory
const nextPage = await paging.next();
// nextPage.data = second page of inventory
const managedObjId: number = 1;
(async() => {
const {
data,
res
} = await client.inventory.detail(managedObjId);
console.log(data)
})();
})();
When I run the .js compiled form the .ts file I get the response below :
authentication to c8y server
And then the execution stops.
The line
console.log('result from authetication', client)
is never called. Seems like something fails in the authentication process and not error is showed.
What I'm doing wrong ?
Thanks.
The first problem might be CORS. You need to enable it if you want to request from a different domain. Here is a guide how to do that in Cumulocity:
Under "Access control", administrators can enable cross-origin
resource sharing or "CORS" on the Cumulocity API.
The second problem could be that you are not running it from a local development server. I mostly use this http-server from npm to quickly test scripts. You can use it the following way:
$ npm install http-server -g
$ http-server
If that all is not helping you might try catch the client to see the error it is throwing:
try {
const client = await Client.authenticate({
user,
password,
tenant
}, baseUrl);
} catch(ex) {
console.log(ex);
}
The exeption might tell you more about what is wrong with your code or if there is a bug in the client.