Skip to content

Commit

Permalink
Add Slack support
Browse files Browse the repository at this point in the history
  • Loading branch information
saltukalakus committed Dec 31, 2020
1 parent 04bb4bc commit 0c4bb7c
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 19 deletions.
8 changes: 8 additions & 0 deletions .env.yml.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
APP_AWS_REGION: us-east-1
APP_OIDC_IAM_ARN: arn:aws:iam::xxxxxxxx:oidc-provider/login-domain.com
OIDC_LOGIN_DOMAIN: login-domain.com
SLACK_WEB_HOOK: https://hooks.slack.com/services/xxxxx/yyyyy/zzzzzzzzzzzz
STARTING_UPDATE_MSG: Starting the AWS OIDC thumprint update
UPDATE_COMPLETED_MSG: AWS OIDC thumprint successfully updated
ERROR_MSG: AWS OIDC thumprint monitor Lambda function failed check CloudWatch logs
RUN_LAMBDA_EVERY_X_MIN: 5
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
# aws-oidc-thumbprint
A lambda function to update the AWS OIDC Identity Provider thumbprint
AWS OIDC Identity Provider needs to pin the login domain certificate. You may find more details regarding this feature [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html)

This tool helps to avoid service distribution by updating the AWS configuration for the certificate thumbprint if the login domain certificate changes. This is useful aspecially if you don't have a control for when the certificate is rotated for the identity provider login domain. E.g. if you are using an identity as a service solution (IaaS) like Auth0, Okta, Azure you may not have the control for the certificate rotation.

The tool is build as a Lambda function which runs every X minutes configured with RUN_LAMBDA_EVERY_X_MIN env variable to check the cert changes and update the thumbprint if needed.

The script sends logs to [AWS CloudWatch](https://aws.amazon.com/cloudwatch/) for certificate rotation. Optionally, you can also send notifications to Slack with [Incomming Webhooks](https://api.slack.com/messaging/webhooks).

**By using this tool you are working-around a security feature. Though it may not be very common to pin the login domain certicate, you are accepting the associated the risks.**

## Conf

Add files for the env variables.
Configure the env variables, by copying the template as .env.yml and fill the necessary variables.

```bash
mv env.yml .env.yml
mv .env.yml.sample .env.yml
```

## Setup
Expand All @@ -16,7 +23,7 @@ mv env.yml .env.yml
yarn
```

## Deploy
## Deploy to AWS with Serverless

```bash
serverless deploy
Expand Down
6 changes: 5 additions & 1 deletion config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
const Conf = {
APP_AWS_REGION: process.env.APP_AWS_REGION,
APP_OIDC_IAM_ARN: process.env.APP_OIDC_IAM_ARN,
OIDC_LOGIN_DOMAIN: process.env.OIDC_LOGIN_DOMAIN
OIDC_LOGIN_DOMAIN: process.env.OIDC_LOGIN_DOMAIN,
SLACK_WEB_HOOK: process.env.SLACK_WEB_HOOK,
STARTING_UPDATE_MSG: process.env.STARTING_UPDATE_MSG,
UPDATE_COMPLETED_MSG: process.env.UPDATE_COMPLETED_MSG,
ERROR_MSG: process.env.ERROR_MSG
}

function Config() {
Expand Down
3 changes: 0 additions & 3 deletions env.yml

This file was deleted.

44 changes: 35 additions & 9 deletions handler.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,60 @@
"use strict";
import AWS from "aws-sdk";
import axios from 'axios';
const sslCertificate = require('get-ssl-certificate-fork');

import Config from './config';

exports.run = async (event, context) => {
exports.run = async () => {
const conf = Config();
const headers = {
'Content-Type': 'application/json'
}
const cert = await sslCertificate.get(conf.OIDC_LOGIN_DOMAIN, 5000, 443, "https:", true);
let fingerprint = cert.issuerCertificate.fingerprint.toLowerCase().replace(/:/g, '');
console.log(fingerprint);

AWS.config.update({ region: conf.APP_AWS_REGION })
const iam = new AWS.IAM()
const options = {
OpenIDConnectProviderArn: conf.APP_OIDC_IAM_ARN
};
iam.getOpenIDConnectProvider(options, (err, data) => {
if (err) console.log(err, err.stack);
if (err) {
console.log(conf.ERROR_MSG, err, err.stack);
if (conf.SLACK_WEB_HOOK) {
axios.post(conf.SLACK_WEB_HOOK, { "text": conf.ERROR_MSG }, {
headers: headers
}).then(() => { }).catch(() => { });
}
}
else {
console.dir(data);
console.dir(data.ThumbprintList);
if (data.ThumbprintList.indexOf(fingerprint) === -1) {
console.log("UPDATE AWS CERT!!!");
console.log(conf.STARTING_UPDATE_MSG);
if (conf.SLACK_WEB_HOOK) {
axios.post(conf.SLACK_WEB_HOOK, { "text": conf.STARTING_UPDATE_MSG }, {
headers: headers
}).then(() => { }).catch(() => { });
}
data.ThumbprintList[0] = fingerprint;
const updateParams = {
OpenIDConnectProviderArn: conf.APP_OIDC_IAM_ARN,
ThumbprintList: data.ThumbprintList
};
iam.updateOpenIDConnectProviderThumbprint(updateParams, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log('Cert successfully updated', data); // successful response
if (err) {
console.log(conf.ERROR_MSG, err, err.stack);
if (conf.SLACK_WEB_HOOK) {
axios.post(conf.SLACK_WEB_HOOK, { "text": conf.ERROR_MSG }, {
headers: headers
}).then(() => { }).catch(() => { });
}
} else {
console.log(conf.UPDATE_COMPLETED_MSG, data);
if (conf.SLACK_WEB_HOOK) {
axios.post(conf.SLACK_WEB_HOOK, { "text": conf.UPDATE_COMPLETED_MSG }, {
headers: headers
}).then(() => { }).catch(() => { });
}
}
});
}
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"author": "[email protected]",
"license": "MIT",
"dependencies": {
"axios": "^0.21.1",
"get-ssl-certificate-fork": "^2.3.5"
},
"devDependencies": {
Expand Down
14 changes: 12 additions & 2 deletions serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ custom:
includeModules:
forceInclude:
- get-ssl-certificate-fork
- axios

provider:
name: aws
Expand All @@ -20,6 +21,10 @@ provider:
APP_AWS_REGION: ${file(.env.yml):APP_AWS_REGION}
APP_OIDC_IAM_ARN: ${file(.env.yml):APP_OIDC_IAM_ARN}
OIDC_LOGIN_DOMAIN: ${file(.env.yml):OIDC_LOGIN_DOMAIN}
SLACK_WEB_HOOK: ${file(.env.yml):SLACK_WEB_HOOK}
STARTING_UPDATE_MSG: ${file(.env.yml):STARTING_UPDATE_MSG}
UPDATE_COMPLETED_MSG: ${file(.env.yml):UPDATE_COMPLETED_MSG}
ERROR_MSG: ${file(.env.yml):ERROR_MSG}

iamRoleStatements:
- Effect: Allow
Expand All @@ -37,5 +42,10 @@ functions:
cron:
handler: handler.run
events:
# Invoke Lambda function every 5 minute
- schedule: cron(0/1 * * * ? *)
# Invoke Lambda function every X minute
- schedule: cron(0/${file(.env.yml):RUN_LAMBDA_EVERY_X_MIN} * * * ? *)
- http:
path: api/run
method: post
integration: lambda
cors: true

0 comments on commit 0c4bb7c

Please sign in to comment.