diff --git a/configmanager/server.js b/configmanager/server.js index 0a535f8..712bb14 100644 --- a/configmanager/server.js +++ b/configmanager/server.js @@ -10,6 +10,13 @@ app.use(hsts({ })) app.use(express.json()) +app.use((err, req, res, next) => { + if (err instanceof SyntaxError && err.status === 400 && 'body' in err) { + return res.status(400).send("Invalid JSON") + } + next(err); +}); + // Define a GET route that accepts a namespace and application parameter app.get('/:namespace/:application', (req, res) => { res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); @@ -141,6 +148,57 @@ app.get('/:namespace/:application', (req, res) => { }); }); +app.post('/:namespace/:application', (req, res) => { + if (req.headers['content-type'] != 'application/json') return res.status(400).send("Invalid JSON"); + const { namespace, application } = req.params; + console.log(req.body) + const body = JSON.stringify(req.body) + console.log(body) + try { + const parsedBody = JSON.parse(body); + console.log(parsedBody) + const newDecoys = parsedBody.decoys; + const newConfig = parsedBody.config; + var filePath = '', configFilePath = '' + if (!namespace.match(/^[a-zA-Z0-9-]+$/) || !application.match(/^[a-zA-Z0-9-]+$/)) { + console.warn(`Bad path provided for decoys config file: ${filePath}, ${configFilePath}`); + } else { + filePath = path.resolve(`/data/cad-${namespace}-${application}.json`); + configFilePath = path.resolve(`/data/config-${namespace}-${application}.json`); + } + const defaultFilePath = `/data/cad-default.json`; + const defaultConfigFilePath = `/data/config-default.json`; + + if (newDecoys){ + fs.access(filePath, fs.constants.F_OK, err => { + if (err) { + fs.access(defaultFilePath, fs.constants.F_OK, err => { + if (err) return res.send("Cannot update decoy config"); + fs.writeFileSync(defaultFilePath, JSON.stringify(newDecoys)); + }) + } else { + fs.writeFileSync(filePath, JSON.stringify(newDecoys)); + } + }) + } + if (newConfig) { + fs.access(configFilePath, fs.constants.F_OK, err => { + if (err) { + fs.access(defaultConfigFilePath, fs.constants.F_OK, err => { + if (err) return res.send("Cannot update config"); + fs.writeFileSync(defaultConfigFilePath, JSON.stringify(newConfig)) + }) + } else { + fs.writeFileSync(configFilePath, JSON.stringify(newConfig)) + } + }) + } + return res.send("Config updated"); + } catch (err) { + return res.status(400).send("Invalid JSON"); + } +}); + app.get('/blocklist', (req, res) => { fs.access("/data/blocklist/blocklist.json", fs.constants.F_OK, err => { if (err) { diff --git a/kyma/configmanager/cad-config.json b/kyma/configmanager/cad-config.json new file mode 100644 index 0000000..6d39f6d --- /dev/null +++ b/kyma/configmanager/cad-config.json @@ -0,0 +1,42 @@ +{ + "config": { + "alert": { + "session": { + "in": "cookie", + "key": "SESSION" + }, + "username": { + "in": "", + "key": "", + "value": "" + } + }, + "server": "", + "respond": [ + { + "source": "", + "behavior": "", + "delay": "", + "duration": "" + } + ], + "blocklistReload": 1 + }, + "decoys": { + "filters": [ + { + "decoy": { + "key": "x-cloud-active-defense", + "separator": "=", + "value": "ACTIVE" + }, + "inject": { + "store": { + "inResponse": ".*", + "as": "header" + } + } + } + ] + } +} \ No newline at end of file diff --git a/kyma/configmanager/edit-cad-config.bat b/kyma/configmanager/edit-cad-config.bat new file mode 100644 index 0000000..7f426f6 --- /dev/null +++ b/kyma/configmanager/edit-cad-config.bat @@ -0,0 +1,75 @@ +@echo off +chcp 65001>nul +setlocal enabledelayedexpansion + +set dir=%~dp0 +set namespace=unknown +set deployment=unknown + +if "%1"=="-h" ( + echo Edit the config for Cloud Active Defense + echo Specify the NAMESPACE and DEPLOYMENT of your app, if none are specify the default config will be edited + echo Edit the cad-config.json file to send your changes to configmanager ^(Changes will overwrite previous config^) + echo. + echo Usage: + echo ./edit-cad-config.bat NAMESPACE DEPLOYMENT + exit +) + +if not defined KUBECONFIG ( + echo Please set KUBECONFIG to connect to the cluster + echo Example: + echo $ENV:KUBECONFIG="PATH\TO\FILE" + exit +) + +if not "%1"=="" ( + for /f "tokens=* delims=" %%A in ('kubectl get ns ^| findstr %1') do set "namespaceResult=%%A" + if not defined namespaceResult ( + echo Namespace doesn't exists, exiting... 🚪 + exit + ) + set namespace=%1 +) +if not "%2"=="" ( + for /f "tokens=* delims=" %%A in ('kubectl get deployment -n %1 ^| findstr %2') do set "deploymentResult=%%A" + if not defined deploymentResult ( + echo Deployment doesn't exists, exiting... 🚪 + exit + ) + set deployment=%2 +) else ( + if not "%1"=="" ( + echo Deployment name is missing, editing default config... 🔧 + ) +) +set filename=%dir%\cad-config.json +set "content=" +for /f "delims=" %%i in (%filename%) do set "content=!content! %%i" +( + echo apiVersion: batch/v1 + echo kind: Job + echo metadata: + echo name: edit-decoys + echo namespace: config-ns + echo spec: + echo template: + echo spec: + echo containers: + echo - name: curl + echo image: curlimages/curl + echo command: ['sh', '-c', 'curl -X POST configmanager-service/namespace/deployment -H "Content-Type: application/json" -d ''!content!'''] + echo restartPolicy: Never +) > %dir%\cad-job.yaml +kubectl apply -f %dir%\cad-job.yaml > nul +del %dir%\cad-job.yaml + +timeout /t 2 /nobreak > nul +for /f "tokens=*" %%i in ('kubectl logs -l job-name^=edit-decoys -n config-ns ^| findstr "Config updated"') do set editResult=%%i +if not defined editResult ( + echo Something went wrong when editing the config ⚠️ +) else ( + echo Updated decoys configuration 💫 +) +kubectl delete job edit-decoys -n config-ns > nul +endlocal \ No newline at end of file