Compare commits

..

3 Commits

Author SHA1 Message Date
bbuchanan9 8176560b2e squash: set noauth in config 2019-07-01 12:49:14 -07:00
bbuchanan9 d6752875e6 feature: ZENKO-1954 Update Dockerfile 2019-07-01 12:44:08 -07:00
bbuchanan9 0cf63d6fe3 feature: S3C-2144 Allow disabling authentication 2019-07-01 12:43:57 -07:00
9 changed files with 172 additions and 10 deletions

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -1,19 +1,16 @@
FROM node:6-slim FROM node:8-slim
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY package.json /usr/src/app COPY . /usr/src/app
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y jq --no-install-recommends \ && apt-get install git -y \
&& npm install --production \ && apt install build-essential -y \
&& rm -rf /var/lib/apt/lists/* \ && apt-get install python -y \
&& apt-get install g++ -y \
&& npm cache clear --force \ && npm cache clear --force \
&& rm -rf ~/.node-gyp \ && npm install --production
&& rm -rf /tmp/npm-*
# Keep the .git directory in order to properly report version
COPY . /usr/src/app
ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh"] ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh"]
CMD [ "npm", "start" ] CMD [ "npm", "start" ]

79
QUICKSTART.md Normal file
View File

@ -0,0 +1,79 @@
# Quickstart
## Server
### Using Docker (~5 minutes)
1. Build the image:
```
$ docker build --tag utapi .
Sending build context to Docker daemon 10.79MB
Step 1/7 : FROM node:8-slim
---> bce75035da07
...
Successfully built 5699ea8e7dec
```
2. Run the image:
```
$ docker run --publish 8100:8100 --detach utapi
25fea1a990b18e7f1f6c76cc5d0c5d564fd6bffb87e1acf5f724db16d602a5b5
```
You should now have a Utapi server running at port 8100.
### Using NPM (~1 minute)
```
$ npm start
> utapi@8.0.0 start /Users/bennettbuchanan/repos/scality/utapi
> node start-server.js
{"name":"Utapi","time":1562008743439,"id":0,"childPid":55156,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743474,"id":5,"childPid":55161,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743493,"id":2,"childPid":55158,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743495,"id":1,"childPid":55157,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743556,"id":4,"childPid":55160,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743575,"id":3,"childPid":55159,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743582,"id":7,"childPid":55163,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743606,"id":9,"childPid":55165,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743619,"id":6,"childPid":55162,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
{"name":"Utapi","time":1562008743639,"id":8,"childPid":55164,"level":"info","message":"Worker started","hostname":"Bennetts-MacBook-Pro-2.local","pid":55155}
```
## Client
See examples in examples/
```js
const http = require('http');
const bucketName = 'test-bucket';
// Get the start and end times for a range of one month.
const start = new Date(2016, 1, 1, 0, 0, 0, 0).getTime();
const end = new Date(2016, 2, 1, 0, 0, 0, 0).getTime() - 1;
const requestBody = JSON.stringify({
buckets: [bucketName],
timeRange: [start, end],
});
const header = {
host: 'localhost',
port: 8100,
method: 'POST',
service: 's3',
path: '/buckets?Action=ListMetrics',
signQuery: false,
body: requestBody,
};
const request = http.request(header, response => {
const body = [];
response.on('data', chunk => body.push(chunk));
response.on('end', () => {
console.log(JSON.parse(body.join('')));
});
});
request.on('error', e => process.stdout.write(`error: ${e.message}\n`));
request.write(requestBody);
request.end();
```

View File

@ -7,10 +7,22 @@
Service Utilization API for tracking resource usage and metrics reporting Service Utilization API for tracking resource usage and metrics reporting
## Quickstart
Please see the [quickstart](/DESIGN.md) guide.
## Design ## Design
Please refer to the [design](/DESIGN.md) for more information. Please refer to the [design](/DESIGN.md) for more information.
To run the server without using the [Signature Version 4 Signing Process](
https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html), set the
environment variable `NO_AUTH` to `'true'`:
```
NO_AUTH=true npm start
```
## Client ## Client
The module exposes a client, named UtapiClient. Projects can use this client to The module exposes a client, named UtapiClient. Projects can use this client to

View File

@ -1,6 +1,7 @@
{ {
"port": 8100, "port": 8100,
"workers": 10, "workers": 10,
"noauth": false,
"healthChecks": { "healthChecks": {
"allowFrom": ["127.0.0.1/8", "::1"] "allowFrom": ["127.0.0.1/8", "::1"]
}, },

View File

@ -39,6 +39,10 @@ if [[ "$HEALTHCHECKS_ALLOWFROM" ]]; then
JQ_FILTERS_CONFIG="$JQ_FILTERS_CONFIG | .healthChecks.allowFrom=[\"$HEALTHCHECKS_ALLOWFROM\"]" JQ_FILTERS_CONFIG="$JQ_FILTERS_CONFIG | .healthChecks.allowFrom=[\"$HEALTHCHECKS_ALLOWFROM\"]"
fi fi
if [[ "$NO_AUTH" ]]; then
JQ_FILTERS_CONFIG="$JQ_FILTERS_CONFIG | .noauth=[\"$NO_AUTH\"]"
fi
if [[ $JQ_FILTERS_CONFIG != "." ]]; then if [[ $JQ_FILTERS_CONFIG != "." ]]; then
jq "$JQ_FILTERS_CONFIG" config.json > config.json.tmp jq "$JQ_FILTERS_CONFIG" config.json > config.json.tmp
mv config.json.tmp config.json mv config.json.tmp config.json

View File

@ -44,6 +44,16 @@ class Config {
this.workers = config.workers; this.workers = config.workers;
} }
this.noauth = false;
if (config.noauth !== undefined) {
assert(typeof config.noauth === 'boolean',
'bad config: noauth must be a boolean');
this.noauth = config.noauth;
}
if (process.env.NO_AUTH !== undefined) {
this.noauth = process.env.NO_AUTH;
}
this.log = { logLevel: 'debug', dumpLevel: 'error' }; this.log = { logLevel: 'debug', dumpLevel: 'error' };
if (config.log !== undefined) { if (config.log !== undefined) {
if (config.log.logLevel !== undefined) { if (config.log.logLevel !== undefined) {

View File

@ -3,6 +3,7 @@ const url = require('url');
const { auth, errors, policies } = require('arsenal'); const { auth, errors, policies } = require('arsenal');
const safeJsonParse = require('../utils/safeJsonParse'); const safeJsonParse = require('../utils/safeJsonParse');
const Vault = require('../lib/Vault'); const Vault = require('../lib/Vault');
const config = require('../lib/Config');
class Router { class Router {
@ -199,6 +200,10 @@ class Router {
*/ */
_authSquared(utapiRequest, cb) { _authSquared(utapiRequest, cb) {
const log = utapiRequest.getLog(); const log = utapiRequest.getLog();
if (config.noauth === 'true') {
log.trace('skipping authentication check');
return process.nextTick(() => cb());
}
const authHeader = utapiRequest.getRequestHeaders().authorization; const authHeader = utapiRequest.getRequestHeaders().authorization;
if (!authHeader || !authHeader.startsWith('AWS4')) { if (!authHeader || !authHeader.startsWith('AWS4')) {
log.trace('missing auth header for v4 auth'); log.trace('missing auth header for v4 auth');

53
tests/unit/testRouter.js Normal file
View File

@ -0,0 +1,53 @@
import assert from 'assert';
import { errors } from 'arsenal';
import { Logger } from 'werelogs';
import config from '../../src/lib/Config';
import Router from '../../src/router/Router';
import UtapiRequest from '../../src/lib/UtapiRequest';
describe('Router', () => {
const router = new Router(config);
describe('::_authSquared', () => {
const log = new Logger('UtapiRequest');
const request = new UtapiRequest().setLog(log);
describe('with unauthorized request', () => {
before(() => {
const incomingMessage = {
headers: {
authorization: false,
},
};
request.setRequest(incomingMessage);
});
after(() => {
request.setRequest(null);
});
it('should return InvalidRequest error', done => {
const expected = errors.InvalidRequest
.customizeDescription('Must use Auth V4 for this request.');
router._authSquared(request, err => {
assert.deepStrictEqual(expected, err);
done();
});
});
describe('with NO_AUTH=true', () => {
before(() => {
process.env.NO_AUTH = 'true';
});
after(() => {
process.env.NO_AUTH = 'false';
});
it('should not return InvalidRequest error', done => {
router._authSquared(request, done);
});
});
});
});
});