Secure Authentication between GN4 and GN5 with JWT
Securing GN5 to GN4 with signed JWT
A more secure way to secure send information to GN4 is to use signed JWT. GN4 will verify they are correctly signed and prevent a malicious actor from faking a GN4 authentication token.
To set this up:
- Generate an RSA private and public key
- Create a JWK Set containing the public key
- Configure GN5
- Configure GN4
Generate an RSA private and public key
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout private.key -out certificate_pub.crt
This will generate:
private.key- use this in GN5. Put this where it is accessible to GN5. This must be secured since the private key is sensitive.certificate_pub.crt- use this in the next step for GN4. Put this where it is accessible to GN4.
Create a JWK Set containing the public key
The standard way of handling JWT signature validation is to use a JWK Set. This is fairly easy to do.
[!WARNING]
If you get an error likeParseException: Missing required "keys" memberthen you've likely forgotten to do the last step (impeding your JWK into another JSON file) that turns the generated JWK into a JWK Set.
- Use https://jwkset.com/generate to convert your
certificate_pub.crtto a JWK.
a. copy the text fromcertificate_pub.crtinto the first section - "PEM encoded key or certificate"
b. choose aKey ID(you'll need this, below)
c.Key Algorithmis "RSA256"
d.Key Useis "Signature"
e. Press "Generate" - Create a file using the output JWT in the following format:
- Save the file and make it accessible by GN4
NOTE: There are other online/offline tools that do this.
Configure GN5
In application.yml:
cloud:
gateway:
mvc:
routes:
...
filters:
- addSimpleJwtGn4SecurityHeader=gn5.to.gn4.trusted.json.auth,file:///Users/db/delme/key/private.key,mykeyid
The parameters to the addSimpleJwtGn4SecurityHeader filter are:
a) name of the header to use (must be the same as the GN4 configuration)
b) URL to the private key (private.key generated above)
c) Name of the Key ID (from above)
Configure GN4
Sent environment variables like this;
[!WARNING] If you are getting errors (especially about the JWT not being valid), the most likely issue is with these settings. Please double check them.
JWTHEADERS_ValidateTokenAudienceClaimValue=g4.from.g5.proxy
JWTHEADERS_ValidateTokenAudience=true
JWTHEADERS_ValidateTokenAudienceClaimName=aud
JWTHEADERS_ValidateTokenExpiry=true
JWTHEADERS_ValidateToken=true
JWTHEADERS_ValidateTokenSignatureURL=file:///Users/db/delme/jws.json
JWTHEADERS_UpdateProfile=false
JWTHEADERS_UpdateGroup=false
JWTHEADERS_RolesHeaderName=gn5.to.gn4.trusted.json.auth
JWTHEADERS_UserNameFormat=JWT
JWTHEADERS_JwtHeaderRoleSource=DB
JWTHEADERS_UserNameJsonPath=username
JWTHEADERS_ValidateTokenAgainstURL=false
JWTHEADERS_UserNameHeaderName=gn5.to.gn4.trusted.json.auth
Audience Validation
This audience is put into the JWT by GN5. It's optional (but recommended) to validate it.
JWTHEADERS_ValidateTokenAudienceClaimValue=g4.from.g5.proxy
JWTHEADERS_ValidateTokenAudience=true
JWTHEADERS_ValidateTokenAudienceClaimName=aud
Token Expiry
Ensure the token hasn't expired yet.
JWTHEADERS_ValidateTokenExpiry=true
Validate Signature
This should be URL to the JWK Set you created, above.
NOTE: see below if you are using a file instead of a https location
JWTHEADERS_ValidateTokenSignatureURL=file:///Users/db/delme/jws.json
Other configuration
This is the meaning of the other configuration options:
JWTHEADERS_UserNameFormat=JWT -- expect identity information to be in a JWT
JWTHEADERS_UserNameJsonPath=username -- json path (inside the JWT payload) of the username
JWTHEADERS_ValidateTokenAgainstURL=false -- do not validate the token against the IDP
JWTHEADERS_UserNameHeaderName=gn5.to.gn4.trusted.json.auth- name of the request header containing the JWT. Must be the same as the GN5 configuration.
JWTHEADERS_UpdateProfile=false - manage user permissions and groups in the DB
JWTHEADERS_UpdateGroup=false- manage user permissions and groups in the DB
JWTHEADERS_JwtHeaderRoleSource=DB - manage user permissions and groups in the DB
JWK Set in File
The older implementation of JWT Headers isn't compatible with file-base URLs for the JWKSet. This is fixed, but it will take a while for this to become "official" through the build chains.
Use python to serve your JWK Set file;
- make a directory and put the JWK Set json file in it
- run:
python3 -m http.server 9000 - Use "http://localhost:9000/jwksets.json" as the JWK Set url
See the python documentation for security related to doing this.