From 04bb4bc075b19feb64cdd75cf4ee1422dab26e69 Mon Sep 17 00:00:00 2001 From: saltukalakus Date: Thu, 31 Dec 2020 21:36:36 +0300 Subject: [PATCH] Move to TypeScript, fix various issues --- config.js => config.ts | 8 +++--- env.yml | 2 +- handler.js | 56 ------------------------------------------ handler.ts | 36 +++++++++++++++++++++++++++ lib/aws.js | 12 --------- package-lock.json | 13 ---------- package.json | 6 ++++- serverless.yml | 32 +++++++++++++++++++++--- tsconfig.json | 24 ++++++++++++++++++ webpack.config.js | 51 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 151 insertions(+), 89 deletions(-) rename config.js => config.ts (59%) delete mode 100644 handler.js create mode 100644 handler.ts delete mode 100644 lib/aws.js delete mode 100644 package-lock.json create mode 100644 tsconfig.json create mode 100644 webpack.config.js diff --git a/config.js b/config.ts similarity index 59% rename from config.js rename to config.ts index 3263fa8..9e4c7ec 100644 --- a/config.js +++ b/config.ts @@ -1,9 +1,11 @@ const Conf = { - APP_IAM_AWS_REGION: process.env.APP_IAM_AWS_REGION, + 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 } -module.exports.config = () => { +function Config() { return Conf -} \ No newline at end of file +} + +export default Config diff --git a/env.yml b/env.yml index 5fbe7d6..15bef5f 100644 --- a/env.yml +++ b/env.yml @@ -1,3 +1,3 @@ -APP_IAM_AWS_REGION: us-east-1 +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 \ No newline at end of file diff --git a/handler.js b/handler.js deleted file mode 100644 index 590b2bf..0000000 --- a/handler.js +++ /dev/null @@ -1,56 +0,0 @@ -"use strict"; -const { aws_iam } = require("./lib/aws"); -const openssl = require('openssl-nodejs'); -const crypto = require('crypto'); -const config = require('./config'); - -module.exports.handler = (event, context) => { - console.log("Lambda executed.."); - const domainName = config().OIDC_LOGIN_DOMAIN; - return openssl(['s_client', '-connect', domainName, '-showcerts'], function (err, buffer) { - let certificateString = buffer.toString(); - let certStart = locations("-----BEGIN CERTIFICATE-----", certificateString); - let certEnd = locations("-----END CERTIFICATE-----", certificateString); - certStart = certStart[certStart.length - 1]; - certEnd = certEnd[certEnd.length - 1]; - certificateString = certificateString.slice(certStart + 28, certEnd); - - const sha1sum = getCertificateFingerprintSha1(certificateString); - - const options = { - OpenIDConnectProviderArn: config().APP_OIDC_IAM_ARN - }; - const iam = aws_iam(); - return iam.getOpenIDConnectProvider(options, (err, data) => { - if (err) console.log(err, err.stack); // an error occurred - else { - const certOnAWS = data.ThumbprintList[data.ThumbprintList.length - 1]; - if (certOnAWS !== sha1sum) { - console.log("UPDATE AWS CERT!!!"); - let newCerts = data.ThumbprintList; - newCerts = newCerts.concat(sha1sum); - const updateParams = { - OpenIDConnectProviderArn: config().APP_OIDC_IAM_ARN, - ThumbprintList: newCerts - }; - return 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 - }); - } - } - }); - }); - - function locations(substring, string) { - let a = [], i = -1; - while ((i = string.indexOf(substring, i + 1)) >= 0) a.push(i); - return a; - } - - function getCertificateFingerprintSha1(certString) { - const rawCert = Buffer.from(certString, "base64"); - const sha1sum = crypto.createHash("sha1").update(rawCert).digest("hex"); - return sha1sum;//.toUpperCase().replace(/(.{2})(?!$)/g, "$1:"); - } -}; \ No newline at end of file diff --git a/handler.ts b/handler.ts new file mode 100644 index 0000000..5d1d0d9 --- /dev/null +++ b/handler.ts @@ -0,0 +1,36 @@ +"use strict"; +import AWS from "aws-sdk"; +const sslCertificate = require('get-ssl-certificate-fork'); +import Config from './config'; + +exports.run = async (event, context) => { + const conf = Config(); + 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); + else { + console.dir(data); + console.dir(data.ThumbprintList); + if (data.ThumbprintList.indexOf(fingerprint) === -1) { + console.log("UPDATE AWS CERT!!!"); + 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 + }); + } + } + }); +}; \ No newline at end of file diff --git a/lib/aws.js b/lib/aws.js deleted file mode 100644 index 8c60537..0000000 --- a/lib/aws.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; - -const aws = require("aws-sdk"); -const config = require('../config'); -let awsServices; - -module.exports.aws_iam = ((awsServices) => { - if (!awsServices.iam) { - awsServices.iam = new aws.IAM({ region: config().APP_IAM_AWS_REGION }); - } - return awsServices.iam; -}).bind(null, awsServices); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 0105edd..0000000 --- a/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "aws-oidc-thumbprint", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "openssl-nodejs": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/openssl-nodejs/-/openssl-nodejs-1.0.5.tgz", - "integrity": "sha512-6+nxZBw96nK1WUk5yIjhv9NRjqtNTfklB508T64BG5TQ8fU1x1rJrc1I3iVW+31KjnYYYwInGTopYxFJa7wMqA==" - } - } -} diff --git a/package.json b/package.json index eca0694..4b0b364 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,10 @@ "author": "saltukalakus@gmail.com", "license": "MIT", "dependencies": { - "openssl-nodejs": "^1.0.5" + "get-ssl-certificate-fork": "^2.3.5" + }, + "devDependencies": { + "aws-sdk": "^2.819.0", + "serverless-bundle": "^4.1.0" } } diff --git a/serverless.yml b/serverless.yml index ec25a96..92bd9b8 100644 --- a/serverless.yml +++ b/serverless.yml @@ -1,15 +1,41 @@ service: aws-oidc-thumbprint +frameworkVersion: ">2.0.0" + +plugins: + - serverless-webpack + +custom: + webpack: + webpackConfig: './webpack.config.js' + includeModules: + forceInclude: + - get-ssl-certificate-fork + provider: name: aws runtime: nodejs12.x + environment: - APP_IAM_AWS_REGION: ${file(.env.yml):APP_IAM_AWS_REGION} + 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} + + iamRoleStatements: + - Effect: Allow + Action: + - iam:GetOpenIDConnectProvider + Resource: + - ${file(.env.yml):APP_OIDC_IAM_ARN} + - Effect: Allow + Action: + - iam:UpdateOpenIDConnectProviderThumbprint + Resource: + - ${file(.env.yml):APP_OIDC_IAM_ARN} functions: cron: - handler: handler + handler: handler.run events: # Invoke Lambda function every 5 minute - - schedule: cron(0/1 * * * ? *) \ No newline at end of file + - schedule: cron(0/1 * * * ? *) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..84c0fac --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "lib": [ + "es2017" + ], + "removeComments": true, + "moduleResolution": "node", + "noUnusedLocals": true, + "noUnusedParameters": true, + "sourceMap": true, + "target": "es2017", + "outDir": "lib" + }, + "include": [ + "./**/*.ts" + ], + "exclude": [ + "node_modules/**/*", + ".serverless/**/*", + ".webpack/**/*", + "_warmup/**/*", + ".vscode/**/*" + ] +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..168adfe --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,51 @@ +const path = require('path'); +const slsw = require('serverless-webpack'); +const nodeExternals = require('webpack-node-externals'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); + +module.exports = { + context: __dirname, + mode: slsw.lib.webpack.isLocal ? 'development' : 'production', + entry: slsw.lib.entries, + devtool: slsw.lib.webpack.isLocal ? 'cheap-module-eval-source-map' : 'source-map', + resolve: { + extensions: ['.mjs', '.json', '.ts'], + symlinks: false, + cacheWithContext: false, + }, + output: { + libraryTarget: 'commonjs', + path: path.join(__dirname, '.webpack'), + filename: '[name].js', + }, + target: 'node', + externals: [nodeExternals()], + module: { + rules: [ + // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader` + { + test: /\.(tsx?)$/, + loader: 'ts-loader', + exclude: [ + [ + path.resolve(__dirname, 'node_modules'), + path.resolve(__dirname, '.serverless'), + path.resolve(__dirname, '.webpack'), + ], + ], + options: { + transpileOnly: true, + experimentalWatchApi: true, + }, + }, + ], + }, + plugins: [ + // new ForkTsCheckerWebpackPlugin({ + // eslint: true, + // eslintOptions: { + // cache: true + // } + // }) + ], +};