Repository: serverless/serverless (JavaScript) — Security

Issue:
AWS credentials file created with serverless config credentials should have more strict permissions!
The AWS credentials files in `~/.aws/credentials` is created by `serverless config credentials` with world-readable permissions, more exactly with `rw-rw-r--` (0664). In a shared environment this is a security issue. The file should be created with `rw-------` (0600) permissions instead.

* *Serverless Framework Version*: 1.4.0
* *Operating System*: Ubuntu 15.10



Discussion:

Resolving patch:
diff --git a/lib/plugins/aws/configCredentials/awsConfigCredentials.js b/lib/plugins/aws/configCredentials/awsConfigCredentials.js
index 03b960a99fd..ea53216e836 100644
--- a/lib/plugins/aws/configCredentials/awsConfigCredentials.js
+++ b/lib/plugins/aws/configCredentials/awsConfigCredentials.js
@@ -1,7 +1,9 @@
 'use strict';
 
 const BbPromise = require('bluebird');
+const constants = require('constants');
 const path = require('path');
+const fs = require('fs');
 const fse = require('fs-extra');
 const os = require('os');
 const _ = require('lodash');
@@ -148,6 +150,15 @@ class AwsConfigCredentials {
 
     return this.serverless.utils.writeFile(this.credentialsFilePath, updatedCredsFileContent)
       .then(() => {
+        // set file permissions to only readable/writable by owner (equivalent to 'chmod 600')
+        // Note: `chmod` doesn't behave as intended on Windows, so skip if we're on Windows.
+        if (os.platform() !== 'win32') {
+          fs.chmodSync(
+            this.credentialsFilePath,
+            (fs.constants || constants).S_IRUSR | (fs.constants || constants).S_IWUSR
+          );
+        }
+
         this.serverless.cli.log(
           `Success! Your AWS access keys were stored under the "${this.options.profile}" profile.`);
       });


Test patch:
diff --git a/lib/plugins/aws/configCredentials/awsConfigCredentials.test.js b/lib/plugins/aws/configCredentials/awsConfigCredentials.test.js
index 21838e17881..8a9561158d7 100644
--- a/lib/plugins/aws/configCredentials/awsConfigCredentials.test.js
+++ b/lib/plugins/aws/configCredentials/awsConfigCredentials.test.js
@@ -2,6 +2,7 @@
 
 const expect = require('chai').expect;
 const sinon = require('sinon');
+const constants = require('constants');
 const fs = require('fs');
 const fse = require('fs-extra');
 const os = require('os');
@@ -215,6 +216,21 @@ describe('AwsConfigCredentials', () => {
         expect(lineByLineContent[2]).to.equal('aws_secret_access_key = my-profile-secret');
       });
     });
+
+    if (os.platform() !== 'win32') {
+      it('should set the permissions of the credentials file to be owner-only read/write', () =>
+        awsConfigCredentials.configureCredentials().then(() => {
+          const fileMode = fs.statSync(credentialsFilePath).mode;
+          const filePermissions = fileMode & ~(fs.constants || constants).S_IFMT;
+
+          const readableByOwnerPermission = (fs.constants || constants).S_IRUSR;
+          const writableByOwnerPermission = (fs.constants || constants).S_IWUSR;
+          const expectedFilePermissions = readableByOwnerPermission | writableByOwnerPermission;
+
+          expect(filePermissions).to.equal(expectedFilePermissions);
+        })
+      );
+    }
   });
 
   describe('#getCredentials()', () => {