Sunday, July 12, 2020

Envoy Control Plane Hello World

Hi,

In this post I would like to explain how to configure Envoy proxy to work with a control plane. I spent some time reading documentation about Envoy and I didn't find nothing for having something up and running for beginners like me. I hope to fill this gap.

To describe Envoy very quickly it is a proxy like Nginx or HAProxy but with the difference that its configuration can be dynamic and piloted through API. I was very curious to set up an example where I can modify the upstream IP address by API.

For more information please refers to Envoy documentation (https://www.envoyproxy.io/docs/envoy/latest/) or this blog article https://blog.envoyproxy.io/service-mesh-data-plane-vs-control-plane-2774e720f7fc which give a bigger picture of control plane and service mesh.

So let's go back to this tutorial. What we will achieve is:



We will use java-control-plane only for EDS functionality. All the rest will be configured statically by a yaml file. What it is interesting is that Envoy can be used in a lot of configuration from fully dynamic by using EDS, CDS, LDS, etc or fully static. We'll take an hybrid approach. Once you understand how it works for EDS it is easy to adapt for the others.

Important concepts with Envoy are listeners (LDS), clusters (CDS) and endpoints (EDS). In our example the listener is configured to be on port 10000. A cluster is a list of endpoints that provide a service (in our example the cluster name is some_service). Endpoints are pairs of IP address/port number associated to a cluster.

Envoy will connect to a control plane to retrieve endpoint configuration (in our example the endpoint 127.0.0.1:8000 is given by the control plane).

First of all you need the Envoy binary. What I did is build it locally by following https://github.com/envoyproxy/envoy/tree/master/ci#building-and-running-tests-as-a-developer. If you go this way I suggest to do it with a release version and not master branch where some unit tests may fail (I did it with v1.14.3 without issue). Another option is to use the docker image.

You will also need the java-control-plane: https://github.com/envoyproxy/java-control-plane (it is easier to use than go-control-plane):

git clone https://github.com/envoyproxy/java-control-plane 

Pre-requisite: 

1) Modify java-control-plane to use it as an EDS

The modification consists in adding an endpoint to some_service cluster in the snapshot. some_service cluster is commented as it is defined by static resource (see content of bootstrap-xds.yaml bellow). Just to help understand, each time you want to change the topology of your mesh you create a new snapshot. The default version of TestMain.java contains two snapshot creation but for this tutorial only the first one is necessary so the second one is commented.

Modify TestMain.java as follow:

 2) Add bootstrap-xds.yaml  to Envoy directory:


Takeaways from this configuration:
- Envoy is listening on port 10000
- Requests to 10000 are sent to the cluster some_service
- The endpoints of cluster some_service are provided by EDS
- EDS server is running on port 12345

Now that all configuration is done, let's start the services

1) Start the upstream

Start an http server listening on port 8000 with python

python3 -m http.server 

2) Start Envoy with bootstrap-xds.yaml configuration

./envoy -c bootstrap-xds.yaml --drain-time-s 1 -l debug 
NB: you can access Envoy stats at http://127.0.0.1:19000



3) Start the control plane

Run TestMain.java from java-control-plane project

4) Verify it works

Make a request to http://127.0.0.1:10000/ and it should be redirected to http://127.0.0.1:8000/

I hope this tutorial can help getting started with Envoy with a very practical example that you can build on.

Sunday, October 15, 2017

Sign SAML 2 AuthnRequest

Hi,

In order to continue on studying SAML requests. Let's complete the code of the last post to add a signature to the AuthnRequest. To run the following code the only requisite is to generate a key pair using Java KeyTool : https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html

Here there is the code :


It will generate the following request :


To be sure the request is valid, you can verify with https://www.samltool.com/validate_authn_req.php

Sunday, October 1, 2017

Generate SAML 2 AuthnRequest by using OpenSAML 3

Hi,

I will start series of posts on SAML 2 about how to generate messages, parsing them and validating them.

First of all, to dig into the subject I really recommend to read the saml technical overview. It has everything needed to understand SAML and it is well written.

In this post I will show how to generate an AuthN request using Java and we will validate the request by using an online tool : https://www.samltool.com/online_tools.php.

You can check how AuthN requests are used in SAML protocol in the following diagram :

This diagram shows the use case "SP-Initiated SSO". Refer to the technical overview mentioned above to have all details.

To generate the AuthnRequest we will use OpenSAML 3. As the website is stating there isn't a lot of documentation on this version of OpenSAML so I took some time to adapt existing code to get the snippet bellow. The original code can be found on this blog :  http://www.john-james-andersen.com/blog/programming/sample-saml-2-0-authnrequest-in-java.html (thanks to the author of this blog)


To make it run, add the following dependencies in your Maven project

<dependency>
    <groupId>org.opensaml</groupId>
    <artifactId>opensaml-core</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
    <groupId>org.opensaml</groupId>
    <artifactId>opensaml-saml-api</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
    <groupId>org.opensaml</groupId>
    <artifactId>opensaml-saml-impl</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
    <groupId>net.shibboleth.utilities</groupId>
    <artifactId>java-support</artifactId>
    <version>7.3.0</version>
</dependency>

The last dependency (net.shibboleth.utilities) is for the pretty print of the SAML message.

By running the code, here there is the SAML AuthnRequest that is generated :

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest
    AssertionConsumerServiceURL="http://sp.example.com/demo1/index.php?acs"
    Destination="http://idp.example.com/SSOService.php"
    ForceAuthn="true" ID="ONELOGIN_6f319749-6db0-4ac6-be72-cb223d5870a4"
    IsPassive="false" IssueInstant="2017-10-01T18:20:31.096Z"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
    Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/demo1/metadata.php</saml2:Issuer>
    <saml2p:NameIDPolicy AllowCreate="true"
        Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" SPNameQualifier="SERVICE_PROVIDER_ID"/>
    <saml2p:RequestedAuthnContext Comparison="minimum">
        <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
    </saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>

The last thing to do is to validate this message, we will use this nice online tool : https://www.samltool.com/validate_authn_req.php. Another way to validate the message would by using OpenSAML itself. It may be the subject of another post on this blog.


I hope this article will help you getting started with SAML message generation. To continue on the subject I will try to add digital signature to this generated message in order to improve security but it will be in another post.

Thank you for reading!

Monday, May 1, 2017

The Name Constraints Extension

A very interesting article about Name Constraints Extension on certificates : https://medium.com/netflix-techblog/bettertls-c9915cd255c0 . @Netflix , Thanks !

Tuesday, December 27, 2016

Secure an API with OAuth2

When it comes to secure a webservice there are several options. One of them is OAuth2 and I will
explain how to have an hello world example running by using Sprint Security OAuth.


Some theory 

To my understanding OAuth2 is all about giving to a third-party a limited access to a ressource. Hum, pretty abstract ... With an example it will be clearer:

Let's say you are reading and article in your favorite dev news website. For example this one : Securing MongoDB Instances

You can notice a Tweet button (*) on top of the article. By clicking it, you will post a tweet in your twitter account with a link to the article you are reading. What it is really going on is that DZone website will be granted an access to your twitter account for a limited time and with limited functionality just to be able to tweet on your behalf. This grant will be given by you by entering your credentials on twitter (**), it is done by redirection and by this action you will allow DZone to access your twitter account. Notice that you never shared your credentials with DZone, you only connected to Twitter.

If it's still not clear, there is an analogy that helped me to understand (it's not from me but I don't remember where I have read it). Imagine you are the owner of a car (the ressource) and you want to go to a fancy restaurant  where someone (third-party) will drive your car (access to a ressource you own) to the restaurant's parking. You don't know this person and give him the key of your car is a risk because he can go away with it. For such situation, car manufacturers came up with a solution which is to provided a special key for the car that only work for a limited distance, it means that you can drive the car only a few meters with this key. So to limit the risk to be stolen from your car, you can give this special key (token) to the restaurant employee.

And if it's still not clear, everything can be found here : The OAuth 2.0 Authorization Framework


Hello world up and running 

For the hello world, what we want to do is to protect the access to a rest API that returns Hello World. We want this API to be callable only by users owning a token provided by an OAuth2 authorization server. Withing OAuth2 framework this use case is called : Bearer Token Usage.

I really encourage to read the documentation about bearer token which is a kind of easier form to use OAuth2 (no redirection), it's perfect for starting. And for hurried readers, have at least a look at the sequence diagram (***).

Well, that's time to make things work. For this, the spring-security-oauth project is bundled with integration tests and we will use the one called Vanilla which is exactly what we want to do.

Quote from the documentation about Vanilla:
"This project shows what you can do with the minimum configuration to set up an Authorization Server and Resource Server"

All you need to do is to clone the project in your machine (git clone https://github.com/spring-projects/spring-security-oauth) and then in the Vanille folder run the command :

mvn spring-boot:run

It will start a tomcat server listening on 8080.

As a client, here are the requests to make if you want to access the protected API
$ curl -H "Accept: application/json" my-client-with-secret:secret@localhost:8080/oauth/token -d grant_type=client_credentials
{... "access_token": "b561ff06-4259-466e-92d8-781db1a51901", ...}
$ TOKEN=b561ff06-4259-466e-92d8-781db1a5190
$ curl -H "Authorization: Bearer $TOKEN" localhost:8080/
Hello World
You basically make a first call by providing a login and password to get a token. Then you can request the API with the token.

One very important thing to keep it mind is that TLS is mandatory with OAuth2. Credentials my-client-with-secret/secret have to be kept secret.

To verify that everything works, try to make a call with an incorrect password and also make a call with an incorrect token. Those calls will be rejected.

For the understanding of this simple scenario be complete, please have a look at Application.java in Vanilla project. The API is protected just by adding @EnableResourceServer annotation. And I let you see how the authorization server is implemented with spring.

Conclusion

OAuth2 is one way to protect an API. By having a simple hello world application running I believe it is easier to understand OAuth2  and by iterating achieve more complex use cases.

I'm planning to make this exact same scenario work with Node.js. With spring it was really straightforward. I hope it will be the same with Node.js but from my first researches I think it will need more work.

Thank you for reading!

(*)


(**)


(***)

Saturday, December 24, 2016

JVM Key size limitation

The Oracle JDK limits the key size it is possible to use for cryptography. Here there is an utility class that can check if your JVM has this limit.


KeyLengthDetector.java (thanks to jehrhardt)

1) Let's run it in a limited JVM :







We can see the key length is limited to 128.

If you can to suppress this limitation , it is possible by installing JCE on the JRE.

2) And now we run it on OpenJDK 9:








key length is : 2147483647

Friday, December 23, 2016

Wycheproof

Monday Google announced the release of Project Wycheproof which are unit tests to verify cryptographic algorithms. It comes with tests for several version of Bouncy Castle, Spongy Castle and for the installation of OpenJDK. 


Let's try to make those tests running by following the documentation 

I'll use an Ubuntu VM (ubuntu-16.04-desktop-amd64) on VirtualBox 


1) Clone the repository 

First of all, make a clone of the github repo :


git clone https://github.com/google/wycheproof.git

2) Install Bazel (requisite)

From documentation, Bazel is a requisite to make the tests run. I'll install it on Ubuntu

Bazel documentation : https://bazel.build/versions/master/docs/install.html


$ echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
$ curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
$ sudo apt-get update && sudo apt-get install bazel

3) Run Tests - BouncyCastleAllTests

We will launch the tests for the latest version of Bouncy Castle

Inside wycheproof folder run the command :

$ bazel test BouncyCastleAllTests

Check the result



More details can be found in testlogs/BouncyCastleAllTests/test.log:



We can see that 11 tests are failed.


4) Run Tests - OpenJDKAllTests


To launch tests on OpenJDK:

$ bazel test OpenJDKAllTests

At the time of writing, 5 tests are failed  with OpenJDK 9

1) testEmptyPlaintext(com.google.security.wycheproof.CipherOutputStreamTest)
2) testKeyGenerationAll(com.google.security.wycheproof.EcKeyTest)
3) testWrongOrderEcdh(com.google.security.wycheproof.EcdhTest)
4) testBiasAll(com.google.security.wycheproof.EcdsaTest)
5) testVectorsAll(com.google.security.wycheproof.RsaSignatureTest)


So, that's it for now. Wycheproof is up and running. It is great stuff for people working with cryptography.