j3k0 / ganomede-directory

Ganomede directory microservice
1 stars 1 forks source link

Multiple `API_SECRET` #21

Open j3k0 opened 7 years ago

j3k0 commented 7 years ago

In order to limit the distribution of the production API_SECRET, I'd like to be able to define multiple inbound API_SECRET for each service, starting with ganomede-directory (for which it might be useful right away).

Suggested solution: API_SECRET is not a comma separated list of valid secret keys.

Advantage: It's backward compatible.

Inconvenient: For outbound requests using API_SECRET, we need to decide which API_SECRET is the one to use. I think it's logical to use the first in the array (apiSecret[0])... Anyway, it's not relevant to ganomede-directory (no outbound request).

Hopefully it's gonna be easy to integrate in other modules as well (when it's needed).

Additional thought (for other services), allow to specify per-service secrets. Like EVENTS_API_SECRET, COORDINATOR_API_SECRET, ... with a fallback to the global API_SECRET[0].

elmigranto commented 7 years ago

Right now we have a secret that one can use to do w/ever on any server. This is problematic, because:


What if we use JWT? Though it would still require secret for verifying signatures, we wouldn't have to include it in every request. Then instead of multiple tokens, we simply specify something like:

// config.js
eventsToken: jwtEncode({
  user: pkg.api,
  for: 'events',
  allows: ['read']
}, process.env.API_SECRET) // "xxx.babsafasf.signature"

// middleware
app.use(middleware.requireJwtFor('events', ['read']}))

This has somewhat similar drawbacks because it allows to create any token with any access level, if secret is ever leaked, but only read access token is transmitted over the wire, and secret lives (hopefuly) securely in process memory. We can come up with more sophisticated issuing scheme later where secret is only know to, say, DIRECTORY, and we just put jwtEncode result in particular service's config.

Older services can have something like jwtEncode({skeletonKey: true}) inside their in/out API_SECRET. Though, with . being in JWT, we'll have to change fake auth.

j3k0 commented 7 years ago

I'll study the suggestions (I don't know anything about JWT). This is low-priority, something to consider to improve overall security after we're done with the rest.

j3k0 commented 7 years ago

Ok, after minimal study, I like the JWT suggestion.

For a smooth transition, I suppose we can do it this way:

Adding more advanced permissions can be a second step. I'm thinking maybe list in the JWT the list of allowed endpoint ("allows": ["GET /events", "POST /events"]).. Anyway: this would be a second step.

The above would be for server-side. Client-side (in places where we used the global API_SECRET for making outgoing requests), I'm thinking to add an optional SERVICE_PORT_8000_API_SECRET env var, which defaults to the global API_SECRET.

Thoughts?