Make one microservice stop trusting its neighbours
Task
Run two small services on one host, show that the back end answers any process that can reach it, then add service-to-service authentication and prove that only the caller holding the credential gets an answer. The lesson says microservices shrink blast radius only if the services do not trust each other implicitly; this lab turns that sentence into status codes.
Steps
- Write
/tmp/ms/orders.py, a back-end service built on Python'shttp.serverthat listens on127.0.0.1:8081and returns a short JSON list of made-up orders at/orders. Start it and confirm thatcurl -s http://127.0.0.1:8081/ordersreturns the list from any shell on the VM. That is implicit trust: being able to reach the service is the only credential it asks for. - Create the credential the front end will present:
openssl rand -hex 32 > /tmp/ms/web.token && chmod 600 /tmp/ms/web.token. On a real platform this identity would be issued by the platform or a secrets manager; a file only its owner can read stands in for it here. - Change
orders.pyso that every request must carryAuthorization: Bearer <token>matching the file, compared withhmac.compare_digest, and anything else gets401and no data. Load the token once at start-up, never from anything the caller sends. - Write
/tmp/ms/web.py, a front-end service on127.0.0.1:8080that calls the back end with that header and relays the result at/. It is the one caller that is supposed to succeed. - Restart both and test three callers: a plain request with no header, a request with a made-up token, and a request through the front end. Record the three status codes.
- Write
/tmp/ms/notes.md: what the token proves (the caller holds a secret), what it does not (which service is calling, once the secret leaks), and why mutual TLS or a platform-issued workload identity is the stronger form of the same control.
Verify
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/orders
curl -s -o /dev/null -w '%{http_code}\n' -H 'Authorization: Bearer not-the-token' http://127.0.0.1:8081/orders
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/
python3 - <<'PY'
import urllib.request, urllib.error
def code(url, hdr=None):
req = urllib.request.Request(url, headers=hdr or {})
try:
return urllib.request.urlopen(req, timeout=5).status
except urllib.error.HTTPError as e:
return e.code
tok = open('/tmp/ms/web.token').read().strip()
res = {
'no credential': code('http://127.0.0.1:8081/orders'),
'wrong credential': code('http://127.0.0.1:8081/orders', {'Authorization': 'Bearer not-the-token'}),
'right credential': code('http://127.0.0.1:8081/orders', {'Authorization': 'Bearer ' + tok}),
'via the front end': code('http://127.0.0.1:8080/'),
}
for k, v in res.items():
print('%-18s %s' % (k, v))
assert res['no credential'] == 401 and res['wrong credential'] == 401, 'the back end still answers callers it should refuse'
assert res['right credential'] == 200 and res['via the front end'] == 200, 'the legitimate caller is refused too - that is an outage, not authentication'
PY
The first two lines must print 401 and the third 200, and both assertions must pass. The 200 through the front end matters as much as the two refusals: a back end that refuses every caller has not been secured, it has been broken, and a control that breaks the service gets switched off.
Notes
The same shape applies to serverless functions, where the execution role and the event trigger are the credential and the caller. In both cases the security gain of small components is real only when each one checks who is calling; otherwise compromising any service on the network is compromising all of them.
This is an independent study companion for CompTIA Security+ SY0-801 and is not produced by or endorsed by CompTIA.