Skip to content

opiproject/opi-strongswan-bridge

Repository files navigation

OPI to strongSwan bridge using vici API

Linters CodeQL OpenSSF Scorecard tests Docker License codecov Go Report Card Go Doc Pulls Last Release GitHub stars GitHub Contributors

This directory contains the security PoC for OPI. This includes reference code for the IPsec APIs. The specification for these APIs can be found here.

I Want To Contribute

This project welcomes contributions and suggestions. We are happy to have the Community involved via submission of Issues and Pull Requests (with substantive content or even just fixes). We are hoping for the documents, test framework, etc. to become a community process with active engagement. PRs can be reviewed by by any number of people, and a maintainer may accept.

See CONTRIBUTING and GitHub Basic Process for more details.

Architecture Diagram

The following is the example architecture we envision for the OPI Security APIs. For IPsec, it utilizes strongSwan to handle IPsec IKE sessions and ESP keys, and assumes a vendor plugin in strongSwan for offloading ESP tunnels into HW acceleration.

OPI Security Architcture

Note that the architecture is meant to show how the OPI Security APIs can work in tandem with the OPI sessionOffload APIs to provide a full IPsec experience, from IKE session creation to ESP session offload.

PoC Diagram

OPI Security PoC Components

Getting started

docker-compose is deprecated. For details, see Migrate to Compose V2.

Run docker-compose up -d

Security gRPC example

Optionally if you need to download modules

docker run --rm -it -v `pwd`:/app -w /app golang:alpine go get all
docker run --rm -it -v `pwd`:/app -w /app golang:alpine go get github.com/opiproject/opi-api/security/proto
docker run --rm -it -v `pwd`:/app -w /app golang:alpine go mod tidy

Run example client via compose (not for production)

$ docker-compose up opi-security-client
[+] Running 4/0
 ⠿ Container opi-strongswan-bridge-vpn-server-1           Running                                                                                                                       0.0s
 ⠿ Container opi-strongswan-bridge-vpn-client-1           Running                                                                                                                       0.0s
 ⠿ Container opi-strongswan-bridge-opi-security-server-1  Running                                                                                                                       0.0s
 ⠿ Container opi-strongswan-bridge-opi-security-client-1  Created                                                                                                                       0.0s
Attaching to opi-strongswan-bridge-opi-security-client-1
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Daemon  [charon]
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Version [5.9.9]
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Sysname [Linux]
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Release [4.18.0-373.el8.x86_64]
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Machine [x86_64]
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 IPsec stats
opi-strongswan-bridge-opi-security-client-1  | Running time: 97 seconds
opi-strongswan-bridge-opi-security-client-1  | Absolute startup time: Feb 09 02:03:29 2023
opi-strongswan-bridge-opi-security-client-1  | Total # of worker threads: 16
opi-strongswan-bridge-opi-security-client-1  | Worker threads currently idle: 11
opi-strongswan-bridge-opi-security-client-1  | Threads processing critical priority jobs: 4
opi-strongswan-bridge-opi-security-client-1  | Threads processing high priority jobs: 0
opi-strongswan-bridge-opi-security-client-1  | Threads processing medium priority jobs: 1
opi-strongswan-bridge-opi-security-client-1  | Threads processing low priority jobs: 0
opi-strongswan-bridge-opi-security-client-1  | Jobs queued with critical priority: 0
opi-strongswan-bridge-opi-security-client-1  | Jobs queued with high priority: 0
opi-strongswan-bridge-opi-security-client-1  | Jobs queued with medium priority: 0
opi-strongswan-bridge-opi-security-client-1  | Jobs queued with low priority: 0
opi-strongswan-bridge-opi-security-client-1  | # of jobs scheduled for timed execution: 4
opi-strongswan-bridge-opi-security-client-1  | Total number of IKE_SAs active: 0
opi-strongswan-bridge-opi-security-client-1  | Number of IKE_SAs in half-open state: 0
opi-strongswan-bridge-opi-security-client-1  | Plugins: charon random nonce x509 constraints pubkey pem openssl kernel-netlink resolve socket-default vici updown eap-identity eap-md5 eap-dynamic eap-tls
opi-strongswan-bridge-opi-security-client-1  | Non-mmap'd space available: 3268608
opi-strongswan-bridge-opi-security-client-1  | Mmap'd space available: 0
opi-strongswan-bridge-opi-security-client-1  | Total number of bytes used: 1479904
opi-strongswan-bridge-opi-security-client-1  | Available but unsued bytes: 1788704
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Loaded: success:"Yes"
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Initiated:
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Returned ikeSas: ikesas:{name:"opi-test"  uniqueid:"3"  version:"2"  ikestate:ESTABLISHED  local_host:"192.168.200.200"  local_port:"4500"  local_id:"[email protected]"  remote_host:"192.168.200.210"  remote_port:"4500"  remote_id:"server.strongswan.org"  initiator:"yes"  initiator_spi:"2a6b4e46c1199545"  responder_spi:"4a9da540276d6147"  encr_alg:"AES_CBC"  encr_keysize:"256"  integ_alg:"HMAC_SHA2_256_128"  prf_alg:"PRF_HMAC_SHA2_256"  dh_group:"CURVE_25519"  established:"0"  rekey_time:"13499"  local_vips:"10.3.0.1"  childsas:{name:"opi-child-2"  protocol:"ESP"  spi_in:"c043deae"  spi_out:"c35fdf8e"  mark_in:"00000000"  mark_out:"00000000"  encr_alg:"AES_GCM_16"  encr_keysize:"256"}}
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Returned connections: connection:{name:"opi-test"  local_addrs:{addr:"192.168.200.200"}  remote_addrs:{addr:"192.168.200.210"}  version:"IKEv2"  rekey_time:14400  unique:"UNIQUE_NO"  children:{name:"opi-child"  mode:"TUNNEL"  rekey_time:3600  dpd_action:"none"  close_action:"none"  local_ts:{ts:{cidr:"dynamic"}}  remote_ts:{ts:{cidr:"10.1.0.0/16"}}}}
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:06 Returned certificates: certs:{hasprivkey:"yes"  data:"MIIB/zCCAYWgAwIBAgIICmApmnHxbpUwCgYIKoZIzj0EAwMwNTELMAkGA1UEBhMCQ0gxDjAMBgNVBAoTBUN5YmVyMRYwFAYDVQQDEw1DeWJlciBSb290IENBMB4XDTIwMDMwOTEzNTkwNloXDTI0MDMwOTEzNTkwNlowPTELMAkGA1UEBhMCQ0gxDjAMBgNVBAoTBUN5YmVyMR4wHAYDVQQDExVjbGllbnQuc3Ryb25nc3dhbi5vcmcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATtv3hJtqlsOU1CciT03FFi0S+BMWhDCoveOLlLBY2xE/Cic+s//fLn7g3UzEG2DPdB++7emFOMlnKBRnhg3sbxejiRFdnjwILZxWo/htyKoB1zbU2ALmjdZV+rQLGZPeejWjBYMB8GA1UdIwQYMBaAFLjSYIqHz0jucV3YUSAjWsGq5feyMCAGA1UdEQQZMBeCFWNsaWVudC5zdHJvbmdzd2FuLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDAjAKBggqhkjOPQQDAwNoADBlAjACrgXJrY3RoERgbfD++vvY8If1P9acT4JDbcTsLNDCgrqooCpU6nawP7Vp5eEbkyoCMQCr+VshJEge7smR6jkZVAqo4N5Zm/GWqCgfJVsmtlie1o4m+cwhpiM2axUIA0osTP8="}  certs:{flag:X509_CERT_FLAG_CA  data:"MIIB3zCCAWWgAwIBAgIIWWpjqeLZ9K8wCgYIKoZIzj0EAwMwNTELMAkGA1UEBhMCQ0gxDjAMBgNVBAoTBUN5YmVyMRYwFAYDVQQDEw1DeWJlciBSb290IENBMB4XDTIwMDMwOTEyMDIwOVoXDTMwMDMwOTEyMDIwOVowNTELMAkGA1UEBhMCQ0gxDjAMBgNVBAoTBUN5YmVyMRYwFAYDVQQDEw1DeWJlciBSb290IENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEaRTgNHa/qa3D/mjvHr/Cr4f20KHiGzlarAXnnDkDUnT7/YEoWBAohYqJFOOeuUc1dsIhXQFN/VVLP+Gyf0pSu272Nx7jA3IwERV12W7cV23YNUJVpNWpY2t61UWiHeh4o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUuNJgiofPSO5xXdhRICNawarl97IwCgYIKoZIzj0EAwMDaAAwZQIwPR1T8MHS+aV9qSueIE9QfPRgEVyvuaz2g4q7DN51SUfypjYoAX+B6BqiR7vfgY2YAjEA65R8XZy0N6LEYgAEPPbQSyCdJudoa4MwidaomSwwgiVDePN356onk/lhURmEQBaZ"}  certs:{}
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:10 Ping stats: &{5 5 0 0 10.3.0.1 10.3.0.1 [195.182µs 243.816µs 274.872µs 287.973µs 286.97µs] 195.182µs 287.973µs 257.762µs 35.126µs}
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:10 Rekeyed IKE_SA opi-test: success:"yes"  matches:1
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:10 Terminate: success:"Yes"  matches:1
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:10 Unloaded: success:"Yes"
opi-strongswan-bridge-opi-security-client-1  | 2023/02/09 02:05:10 GRPC connection closed successfully
opi-strongswan-bridge-opi-security-client-1  | <nil>
opi-strongswan-bridge-opi-security-client-1 exited with code 0

gRPC CLI

From https://github.com/grpc/grpc-go/blob/master/Documentation/server-reflection-tutorial.md

Alias

alias grpc_cli='docker run --network=opi-strongswan-bridge_internet --rm -it namely/grpc-cli'

See services

 $ grpc_cli ls opi-security-server:50051
grpc.reflection.v1alpha.ServerReflection
opi_api.security.v1.IPsec

See commands

$ grpc_cli ls opi-security-server:50051 opi_api.security.v1.IPsec -l
filename: ipsec.proto
package: opi_api.security.v1;
service IPsec {
  rpc IPsecVersion(opi_api.security.v1.IPsecVersionReq) returns (opi_api.security.v1.IPsecVersionResp) {}
  rpc IPsecStats(opi_api.security.v1.IPsecStatsReq) returns (opi_api.security.v1.IPsecStatsResp) {}
  rpc IPsecInitiate(opi_api.security.v1.IPsecInitiateReq) returns (opi_api.security.v1.IPsecInitiateResp) {}
  rpc IPsecTerminate(opi_api.security.v1.IPsecTerminateReq) returns (opi_api.security.v1.IPsecTerminateResp) {}
  rpc IPsecRekey(opi_api.security.v1.IPsecRekeyReq) returns (opi_api.security.v1.IPsecRekeyResp) {}
  rpc IPsecListSas(opi_api.security.v1.IPsecListSasReq) returns (opi_api.security.v1.IPsecListSasResp) {}
  rpc IPsecListConns(opi_api.security.v1.IPsecListConnsReq) returns (opi_api.security.v1.IPsecListConnsResp) {}
  rpc IPsecListCerts(opi_api.security.v1.IPsecListCertsReq) returns (opi_api.security.v1.IPsecListCertsResp) {}
  rpc IPsecLoadConn(opi_api.security.v1.IPsecLoadConnReq) returns (opi_api.security.v1.IPsecLoadConnResp) {}
  rpc IPsecUnloadConn(opi_api.security.v1.IPsecUnloadConnReq) returns (opi_api.security.v1.IPsecUnloadConnResp) {}
}

See methods

$ grpc_cli ls opi-security-server:50151 opi_api.security.v1.IPsec.IPsecLoadConn -l
  rpc IPsecLoadConn(opi_api.security.v1.IPsecLoadConnReq) returns (opi_api.security.v1.IPsecLoadConnResp) {}

See messages

$ grpc_cli type opi-security-server:50051 opi_api.security.v1.IPsecCreateRequest
message IPsecCreateRequest {
  .opi_api.security.v1.TunnelInterfaces tunnel = 1 [json_name = "tunnel"];
  .opi_api.security.v1.SecurityPolicyDatabases policy = 2 [json_name = "policy"];
  .opi_api.security.v1.SecurityAssociations sa = 3 [json_name = "sa"];
}

Call remote method

$ grpc_cli call opi-security-server:50051 IPsecDelete  "id: {value: 'bla'}"
connecting to opi-security-server:50051
id {
  value: "bla"
}
Rpc succeeded with OK status

Server log

opi-security-server_1  | 2022/08/05 17:19:18 IPsecDelete: Received: value:"bla"

Architecture

The architecture of the PoC includes the following components:

  • strongSwan server container
  • strongSwan client container
  • OPI Security API server container
  • OPI Security API client container

OPI Security PoC Components

Create

On creation of a new IPsec tunnel, the OPI API Security server will do the following:

  • Receive the API call on the northbound side
  • Using the vici API
    • Program the new IKE session into strongSwan
    • Trigger the connection
    • Offload the ESP session using the sessionOffload API

Delete

On deletion of an IPsec tunnel, the OPI API Security server will do the following:

  • Receive the API call on the northbound side
  • Using the vici API:
    • Down the connection
    • Delete the IKE session from strongSwan