title |
---|
Configure SSL/TLS |
NOTE: This article describes MagicOnion v3 configuration.
As official gRPC doc notes gRPC supports SSL/TLS, and MagicOnion also support SSL/TLS.
gRPC has SSL/TLS integration and promotes the use of SSL/TLS to authenticate the server, and to encrypt all the data exchanged between the client and the server. Optional mechanisms are available for clients to provide certificates for mutual authentication
Let's use samples/ChatApp/ChatApp.Server for server project, and samples/ChatApp/ChatApp.Unity for client project.
This section explains how to setup "SSL/TLS MagicOnion on AWS" with following 5 steps.
- Generate self-signed certificate
- Server configuration
- Kubernetes deployments
- Enable ALPN on NLB
- Client configuration
AWS LoadBalancer supports ALPN with ALB (Application Load Balancer) and NLB (Network Load Balancer), however ALB doesn't support HTTP/2 to the backend group, you must use NLB.
Connection flow
To establish HTTP/2 between Client and Server with NLB, gRPC connection should follow full HTTP/2 over TLS
.
You must establish TLS connection for both "NLB (Listener) & Client" and "NLB (TargetGroup) & Server".
Server <-- TLS (Self-signed) --> NLB <-- TLS (ACM) --> Client
- NLB (Listener) & Client: NLB Listener work with ACM. Client use Gprpc.Core.dll embedded roots.pem by default.
- NLB (TargetGroup) & Server: You need set TargetGroup as TLS and listen gRPC Server as TLS. You can use self-signed cert, Let's Encrypt and others. (This README use self-signed cert.)
Following command will create 3 files server.csr
, server.key
and server.crt
.
gRPC/MagicOnion Server requires server.crt and server.key.
# move to your server project
$ cd samples/ChatApp/ChatApp.Server
# generate certificates
# NOTE: CN=xxxx should match domain name to magic onion server pointing domain name
$ openssl genrsa 2048 > server.key
$ openssl req -new -sha256 -key server.key -out server.csr -subj "/C=JP/ST=Tokyo/L=Tokyo/O=MagicOnion Demo/OU=Dev/CN=*.example.com"
$ openssl x509 -req -in server.csr -signkey server.key -out server.crt -days 7300 -extensions server
Please modify /C=JP/ST=Tokyo/L=Tokyo/O=MagicOnion Demo/OU=Dev/CN=*.example.com
to your domain.
Make sure CN=xxxx
should match to domain that your MagicOnion Server will recieve request from your client.
ATTENTION: server.key is very sensitive file, while server.crt can be public. DO NOT COPY server.key to your client.
NOTE: Server will use server.crt and server.key, if you didn't copy OpenSSL generated
server.crt
andserver.key
, please back to generate certificate section and copy them.
Open samples/ChatApp/ChatApp.Server/ChatApp.Server.csproj
and add following lines before </Project>
.
<ItemGroup>
<Folder Include="LinkFromUnity\" />
</ItemGroup>
<!-- FOR SSL/TLS SUPPORT -->
<ItemGroup>
<None Update="server.crt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="server.key">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
MagicOnion.Hosting supports specifing certificate with appsettings.json.
{
"MagicOnion": {
"ServerPorts": [
{
"Host": "0.0.0.0",
"Port": 12345,
"UseInsecureConnection": false,
"ServerCredentials": [
{
"CertificatePath": "./server.crt",
"KeyPath": "./server.key"
}
]
}
]
}
}
Now dotnet publish
output dll and certificates, generate your docker image and push it.
cd samples/ChatApp
docker build -t chatapp_magiconion:latest -f ChatApp.Server/Dockerfile .
docker tag chatapp_magiconion:latest your-image:latest
docker push your-image:latest
Apply yaml to configure EKS deployments.
# replace with your ACM Arn and others.
ACM=arn:aws:acm:ap-northeast-1:123456781234:certificate/12345678-abcd-1234-efgh-1234abcd5678
DOMAIN=your-domain.com
IMAGE=your-image:latest
cat ./samples/ChatApp/k8s/nlb_acm.yaml \
| sed -e "s|arn:aws:acm:ap-northeast-1:123456781234:certificate/12345678-abcd-1234-efgh-1234abcd5678|${ACM}|g" \
| sed -e "s|nlb.example.com|${DOMAIN}|g" \
| sed -e "s|cysharp/magiconion_sample_chatapp:3.0.13-chatapp|${IMAGE}|g" \
| kubectl apply -f -
Current Kubernetes Service AWS integration not support annotations for ALPN.
Configure NLB Listener's ALPN policy to HTTP2Preferred
by following command, or via AWS Console.
$ dns=$(kubectl get svc chatapp-svc -o=jsonpath='{.status.loadBalancer.ingress[0].hostname}')
$ nlb_arn=$(aws elbv2 describe-load-balancers | jq -r ".LoadBalancers[] | select(.DNSName == \"${dns}\") | .LoadBalancerArn")
$ listeners=$(aws elbv2 describe-listeners --load-balancer-arn "${nlb_arn}" | jq -r ".Listeners[].ListenerArn")
$ for listner in "${listeners[@]}"; do aws elbv2 modify-listener --listener-arn "${listner}" --alpn-policy HTTP2Preferred; done
NOTE: Client will use Grpc.Core.dll embedded roots.pem when not specify cert file with
SslCredentials
instance.
Open samples/ChatApp/ChatApp.Unity/Assets/ChatComponent.cs
, channel creation is defined as ChannelCredentials.Insecure
in InitializeClient()
.
What you need tois change this line to use SslCredentials
.
this.channel = new Channel("localhost", 12345, ChannelCredentials.Insecure);
Replace this line to following.
this.channel = new Channel("NLB.YOUR_DOMAIN.com", 12345, new SslCredentials());
Play on Unity Editor and confirm Unity MagicOnion Client can connect to MagicOnion Server.
NOTE: If there are any trouble establish SSL/TLS connection, Unity Client will show
disconnected server.
log.
This section explains how to setup "SSL/TLS MagicOnion on localhost" with following 4 steps.
- Generate self-signed certificate
- Simulate dummy domain via hosts
- Server configuration
- Client configuration
Connection flow
Server <-- TLS (Self-signed) --> Client
Certificates are required to establish SSL/TLS with Server/Client channel connection. Let's use OpenSSL to create required certificates.
Following command will create 3 files server.csr
, server.key
and server.crt
.
gRPC/MagicOnion Server requires server.crt and server.key, and Client require server.crt.
# move to your server project
$ cd MagicOnion/samples/ChatApp/ChatApp.Server
# generate certificates
# NOTE: CN=xxxx should match domain name to magic onion server pointing domain name
$ openssl genrsa 2048 > server.key
$ openssl req -new -sha256 -key server.key -out server.csr -subj "/C=JP/ST=Tokyo/L=Tokyo/O=MagicOnion Demo/OU=Dev/CN=*.example.com"
$ openssl x509 -req -in server.csr -signkey server.key -out server.crt -days 7300 -extensions server
# server will use server.crt and server.key, leave generated certificates.
# client will use server.crt, copy certificate to StreamingAssets folder.
$ mkdir ../ChatApp.Unity/Assets/StreamingAssets
$ cp server.crt ../ChatApp.Unity/Assets/StreamingAssets/server.crt
Please modify /C=JP/ST=Tokyo/L=Tokyo/O=MagicOnion Demo/OU=Dev/CN=*.example.com
your domain.
Make sure CN=xxxx
should match to domain that your MagicOnion Server will recieve request from your client.
ATTENTION: server.key is very sensitive file, while server.crt can be public. DO NOT COPY server.key to your client.
Editting hosts
file is the simple way to redirect dummy domain request to your localhost.
Let's set your CN to you hosts, example is dummy.example.com
.
Open hosts file and add your entry.
# NOTE: edit hosts to test on localhost
# Windows: (use scoop to install sudo, or open elevated cmd or notepad.)
PS> sudo notepad c:\windows\system32\drivers\etc\hosts
# macos:
$ sudo vim /private/etc/hosts
# Linux:
$ sudo vim /etc/hosts
Entry format would be similar to this, please follow to your platform hosts rule.
127.0.0.1 dummy.example.com
After modifying hosts, ping
to your dummy domain and confirm localhost is responding.
$ ping dummy.example.com
pinging to dummy.example.com [127.0.0.1] 32 bytes data:
127.0.0.1 response: bytecount =32 time <1ms TTL=128
NOTE: Server will use server.crt and server.key, if you didn't copy OpenSSL generated
server.crt
andserver.key
, please back to generate certificate section and copy them.
Open samples/ChatApp/ChatApp.Server/ChatApp.Server.csproj
and add following lines before </Project>
.
<ItemGroup>
<Folder Include="LinkFromUnity\" />
</ItemGroup>
<!-- FOR SSL/TLS SUPPORT -->
<ItemGroup>
<None Update="server.crt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="server.key">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
MagicOnion.Hosting supports specifing certificate with appsettings.json.
{
"MagicOnion": {
"ServerPorts": [
{
"Host": "0.0.0.0",
"Port": 12345,
"UseInsecureConnection": false,
"ServerCredentials": [
{
"CertificatePath": "./server.crt",
"KeyPath": "./server.key"
}
]
}
]
}
}
Debug run server on Visual Studio, any IDE or docker.
NOTE: Set
DOTNET_ENVIRONMENT=Production
to use tls configured appsettings.json
D0729 11:08:21.767387 Grpc.Core.Internal.NativeExtension gRPC native library loaded successfully.
Application started. Press Ctrl+C to shut down.
Hosting environment: Production
NOTE: Client will use server.crt, if you didn't copy OpenSSL generated
server.crt
andserver.key
, please back to generate certificate section and copy it.
Open samples/ChatApp/ChatApp.Unity/Assets/ChatComponent.cs
, channel creation is defined as ChannelCredentials.Insecure
in InitializeClient()
.
What you need tois change this line to use SslCredentials
.
this.channel = new Channel("localhost", 12345, ChannelCredentials.Insecure);
Replace this line to following.
var serverCred = new SslCredentials(File.ReadAllText(Path.Combine(Application.streamingAssetsPath, "server.crt")));
this.channel = new Channel("dummy.example.com", 5001, serverCred);
Play on Unity Editor and confirm Unity MagicOnion Client can connect to MagicOnion Server.
NOTE: If there are any trouble establish SSL/TLS connection, Unity Client will show
disconnected server.
log.