1+ #!/usr/bin/env node
2+ 'use strict' ;
3+
4+ const path = require ( 'path' )
5+ const simplify = require ( 'simplify-sdk' )
6+ const provider = require ( 'simplify-sdk/provider' )
7+ const utilities = require ( 'simplify-sdk/utilities' )
8+ const CBEGIN = '\x1b[32m'
9+ const CERROR = '\x1b[31m'
10+ const CRESET = '\x1b[0m'
11+ const CDONE = '\x1b[37m'
12+ const opName = `SecOps`
13+
14+ var argv = require ( 'yargs' )
15+ . usage ( 'simplify-secops status|patch|check|metric [options]' )
16+ . string ( 'input' )
17+ . alias ( 'i' , 'input' )
18+ . describe ( 'input' , 'Input file contains function list' )
19+ . default ( 'input' , 'functions.csv' )
20+ . string ( 'hours' )
21+ . describe ( 'hours' , 'How many hours since now eg: 12 - last 12 hours' )
22+ . alias ( 'h' , 'hours' )
23+ . string ( 'periods' )
24+ . describe ( 'periods' , 'Time resolution periods eg: 5 10 30 60 N*60 in seconds' )
25+ . alias ( 't' , 'periods' )
26+ . string ( 'profile' )
27+ . describe ( 'profile' , 'AWS Profile configuration' )
28+ . alias ( 'p' , 'profile' )
29+ . default ( 'profile' , 'default' )
30+ . string ( 'region' )
31+ . describe ( 'region' , 'AWS Specific Region' )
32+ . alias ( 'r' , 'region' )
33+ . default ( 'region' , 'eu-west-1' )
34+ . demandOption ( [ 'i' ] )
35+ . demandCommand ( 1 )
36+ . argv ;
37+
38+ var configInputFile = argv . input || 'functions.csv'
39+ var scanOutput = { }
40+ var cmdOPS = ( argv . _ [ 0 ] || 'status' ) . toUpperCase ( )
41+ var lineIndex = 0
42+ var funcList = [ ]
43+
44+ var files = require ( 'fs' ) . readFileSync ( path . join ( __dirname , configInputFile ) , 'utf-8' ) . split ( / \r ? \n / )
45+ var headers = files [ lineIndex ++ ]
46+
47+ function analyseOrPatch ( args ) {
48+ const { functionInfo, triggerEvent, logRetention, customKmsArn, secureFunction, secureLog } = args
49+ return new Promise ( ( resolve , reject ) => {
50+ functionInfo . KMSKeyArn = functionInfo . KMSKeyArn || customKmsArn
51+ if ( functionInfo . KMSKeyArn ) {
52+ if ( cmdOPS === 'PATCH' ) {
53+ let functionConfig = {
54+ FunctionName : functionInfo . FunctionName
55+ }
56+ if ( secureFunction /** enabled */ ) {
57+ functionConfig . KMSKeyArn = functionInfo . KMSKeyArn
58+ }
59+ simplify . updateFunctionConfiguration ( {
60+ adaptor : provider . getFunction ( ) ,
61+ functionConfig : functionConfig
62+ } ) . then ( functionOutput => {
63+ /** record new SHA256 Code Here */
64+ simplify . enableOrDisableLogEncryption ( {
65+ adaptor : provider . getKMS ( ) ,
66+ logger : provider . getLogger ( ) ,
67+ functionInfo : functionInfo ,
68+ retentionInDays : logRetention ,
69+ enableOrDisable : secureLog
70+ } ) . then ( function ( data ) {
71+ console . log ( `${ CBEGIN } Simplify${ CRESET } | \x1b[32m[DONE]\x1b[0m ${ cmdOPS } ${ functionInfo . FunctionName } : Configured secure logs with ${ logRetention } days!` )
72+ resolve ( args )
73+ } ) . catch ( function ( err ) {
74+ reject ( `${ err } ` )
75+ } )
76+ } ) . catch ( function ( err ) {
77+ reject ( `${ err } ` )
78+ } )
79+ } else if ( cmdOPS === 'CHECK' ) {
80+ console . log ( `${ CBEGIN } Simplify${ CRESET } | \x1b[32m[GOOD]\x1b[0m ${ cmdOPS } ${ functionInfo . FunctionName } : ${ functionInfo . KMSKeyArn ? 'Has already configure with KMS Custom Key' : 'Provide a KMS Custom Key to apply a PATCH' } !` )
81+ resolve ( args )
82+ } else {
83+ resolve ( args )
84+ }
85+ } else {
86+ if ( cmdOPS === 'PATCH' ) {
87+ if ( secureFunction ) {
88+ console . error ( `${ CBEGIN } Simplify${ CRESET } | \x1b[31m[ERROR]\x1b[0m ${ cmdOPS } ${ functionInfo . FunctionName } : Provide a KMS Custom Key ARN!` )
89+ }
90+ resolve ( args )
91+ } else if ( cmdOPS === 'CHECK' ) {
92+ if ( secureFunction ) {
93+ console . log ( `${ CBEGIN } Simplify${ CRESET } | \x1b[33m[WARN]\x1b[0m ${ cmdOPS } ${ functionInfo . FunctionName } : Provide a KMS Custom Key ARN!` )
94+ }
95+ resolve ( args )
96+ } else {
97+ resolve ( args )
98+ }
99+ }
100+ } )
101+ }
102+ const secOpsFunctions = function ( files , callback ) {
103+ const currentLine = files [ lineIndex ++ ]
104+ if ( currentLine ) {
105+ const parts = currentLine . split ( ',' )
106+ if ( parts . length >= 7 ) {
107+ const functionArn = `arn:aws:lambda:${ parts [ 0 ] } :${ parts [ 1 ] } :function:${ parts [ 2 ] } `
108+ const triggerEvent = parts [ 3 ] || 'Lambda'
109+ const logRetention = parts [ 4 ] || 90
110+ const customKmsArn = parts [ 5 ] ? `arn:aws:kms:${ parts [ 0 ] } :${ parts [ 1 ] } :key/${ parts [ 5 ] } ` : undefined
111+ const secureFunction = JSON . parse ( ( parts [ 6 ] || 'false' ) . toLowerCase ( ) )
112+ const secureLog = JSON . parse ( ( parts [ 7 ] || 'false' ) . toLowerCase ( ) )
113+ simplify . getFunctionConfiguration ( {
114+ adaptor : provider . getFunction ( ) ,
115+ functionConfig : { FunctionName : functionArn }
116+ } ) . then ( function ( functionInfo ) {
117+ if ( ! scanOutput [ functionInfo . FunctionName ] ) {
118+ scanOutput [ functionInfo . FunctionName ] = { }
119+ }
120+ scanOutput [ functionInfo . FunctionName ] = functionInfo
121+ analyseOrPatch ( { functionInfo, triggerEvent, logRetention, customKmsArn, secureFunction, secureLog } ) . then ( res => {
122+ funcList . push ( { ...res } )
123+ if ( lineIndex >= files . length ) {
124+ callback && callback ( funcList )
125+ } else {
126+ secOpsFunctions ( files , callback )
127+ }
128+ } )
129+ } ) . catch ( err => console . log ( `${ CBEGIN } Simplify${ CRESET } | ERROR: ${ err } ` ) )
130+ }
131+ } else {
132+ callback && callback ( funcList )
133+ }
134+ }
135+
136+ try {
137+ var config = simplify . getInputConfig ( {
138+ Region : argv . region || 'eu-west-1' ,
139+ Profile : argv . profile || 'default' ,
140+ Bucket : { Name : 'default' }
141+ } )
142+ provider . setConfig ( config ) . then ( function ( ) {
143+ if ( headers . startsWith ( 'Region' ) ) {
144+ secOpsFunctions ( files , function ( list ) {
145+ if ( cmdOPS === 'METRIC' ) {
146+ let startDate = new Date ( )
147+ startDate . setHours ( startDate . getHours ( ) - ( parseInt ( argv . hours || 12 ) ) )
148+ simplify . getFunctionMetricData ( {
149+ adaptor : provider . getMetrics ( ) ,
150+ functions : list . map ( l => { return { FunctionName : l . FunctionName } } ) ,
151+ periods : parseInt ( argv . periods || 300 ) ,
152+ startDate : startDate ,
153+ endDate : new Date ( )
154+ } ) . then ( metrics => {
155+ metrics . MetricDataResults . map ( m => {
156+ let mData = [ ]
157+ if ( ! m . Values . length ) {
158+ mData . push ( {
159+ Label : m . Label ,
160+ Timestamp : new Date ( ) . toISOString ( ) ,
161+ Value : '0'
162+ } )
163+ } else {
164+ for ( let i = 0 ; i < m . Values . length ; i ++ ) {
165+ mData . push ( {
166+ Label : m . Label ,
167+ Timestamp : m . Timestamps [ i ] ,
168+ Value : m . Values [ i ]
169+ } )
170+ }
171+ }
172+ utilities . printTableWithJSON ( mData )
173+ } )
174+ } ) . catch ( err => console . error ( `${ err } ` ) )
175+ } else {
176+ const outputTable = list . map ( func => {
177+ return {
178+ FunctionName : func . functionInfo . FunctionName . truncateRight ( 20 ) ,
179+ LastModified : new Date ( func . functionInfo . LastModified ) . toISOString ( ) ,
180+ State : func . functionInfo . State ,
181+ CodeSize : func . functionInfo . CodeSize ,
182+ Timeout : func . functionInfo . Timeout ,
183+ CodeSha256 : func . functionInfo . CodeSha256 . truncateLeft ( 5 ) ,
184+ TriggerEvent : func . triggerEvent . truncateRight ( 12 ) ,
185+ LogRetention : func . logRetention ,
186+ CustomKmsArn : ( func . customKmsArn || '' ) . truncateLeft ( 12 ) ,
187+ SecureFunction : func . secureFunction ? ( func . functionInfo . KMSKeyArn ? 'OK' : 'YES - PATCH' ) : ( func . functionInfo . KMSKeyArn ? 'NO - PATCH' : 'OK' ) ,
188+ SecureLog : func . secureLog ? ( func . functionInfo . KMSKeyArn ? 'OK' : 'YES - PATCH' ) : ( func . functionInfo . KMSKeyArn ? 'NO - PATCH' : 'OK' )
189+ }
190+ } )
191+ utilities . printTableWithJSON ( outputTable )
192+ }
193+ } )
194+ }
195+ } )
196+ } catch ( err ) {
197+ simplify . finishWithErrors ( `${ opName } -LoadConfig` , err )
198+ }
0 commit comments