{"id":16716685,"url":"https://github.com/dinosaure/contruno","last_synced_at":"2025-03-21T20:34:17.002Z","repository":{"id":41812279,"uuid":"387777480","full_name":"dinosaure/contruno","owner":"dinosaure","description":"A TLS termination proxy as a MirageOS","archived":false,"fork":false,"pushed_at":"2024-10-03T12:57:40.000Z","size":191,"stargazers_count":13,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-13T21:26:44.165Z","etag":null,"topics":["letsencrypt","mirageos","tls","unikernel"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dinosaure.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-20T12:01:40.000Z","updated_at":"2024-10-03T12:57:41.000Z","dependencies_parsed_at":"2024-07-17T14:34:46.852Z","dependency_job_id":null,"html_url":"https://github.com/dinosaure/contruno","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dinosaure%2Fcontruno","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dinosaure%2Fcontruno/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dinosaure%2Fcontruno/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dinosaure%2Fcontruno/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dinosaure","download_url":"https://codeload.github.com/dinosaure/contruno/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221819013,"owners_count":16885870,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["letsencrypt","mirageos","tls","unikernel"],"created_at":"2024-10-12T21:27:13.633Z","updated_at":"2024-10-28T10:51:30.196Z","avatar_url":"https://github.com/dinosaure.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eContruno\u003c/h1\u003e\n\u003ch4 align=\"center\"\u003eA TLS termination proxy as an unikernel\u003c/h4\u003e\n\u003chr\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/dinosaure/contruno/blob/main/img/uno.jpg?raw=true\"\u003e\n\u003c/p\u003e\n\n`contruno` is a TLS termination proxy is a proxy server that acts as an\nintermediary point between client and server applications, and is used to\nestablish TLS tunnels with let's encrypt certificates.\n\nFrom a Git repository which contains TLS certificates and private keys\ndelivered by let's encrypt, the user is able launch into its private network a\nsimple HTTP server. `contruno` does the bridge between the client which\ninitiates a TLS tunnel with a specific certificate from the Git repository and\nits HTTP server.\n\n`contruno` handles expiration of certificates and do the let's encrypt\nchallenge (the HTTP challenge) when one of is expired. Then, it renegociates\ncurrent connections with the new certificate and save it (with its private key)\ninto the Git repository.\n\nIf `contruno` shutdowns, you can restart it and, from the same Git repository,\nit will restart the TLS termination proxy with all current certificates.\n\n## How to use it?\n\n**status**: experimental\n\n`contruno` wants few informations:\n- The Git repository\n- The SSH seed to generate (via _fortuna_) the private SSH key\n- A password\n- If you want to use production ready certificates or not\n- Email, certificate seed and account seed (optional)\n\nThe Git repository should be well formed. A tool exists, `contruno.add` to put\na new certificate (with its private key) into the Git repository and signals\nthe unikernel (via the password) to reload certificates.\n\n### How to compile the project?\n\nThe `contruno` repository provides three things: a `contruno` OCaml library, a\n`contruno.add` binary (used to configure the unikernel), and the `contruno`\nunikernel itself.\n\nFirst, let's install the library and binary as opam packages:\n```sh\ngit clone https://github.com/dinosaure/contruno \u0026\u0026 cd contruno\nopam pin -y .\n```\n\nBuilding the unikernel requires mirage and dune:\n```\nopam install 'mirage\u003e=4.0' 'dune\u003e=3.0'\n```\n\nNext, let's build the unikernel. Due to a build system limitation, we need to\ncopy the sources in `unikernel/` somewhere else before building:\n```sh\ncp -r unikernel /tmp/ \u0026\u0026 cd /tmp/unikernel/\nmirage configure -t hvt  # hvt for the KVM target\nmake depends\nmirage build\n```\n\nAnd we now have a unikernel image `dist/contruno.hvt` ready to be deployed.\n\n### How to deploy the _unikernel_?\n\nLet's start with a simple network topology with a private network 10.0.0.0 on a\nbridge `br0`:\n```sh\n$ cat \u003e\u003e/etc/network/interfaces \u003c\u003cEOF\n\nauto br0\niface br0 inet static\n  address 10.0.0.1\n  netmask 255.255.255.0\n  broadcast 10.0.0.255\n  bridge_ports none\n  bridge_stp off\n  bridge_fd 0\n  bridge_maxwait 0\nEOF\n$ systemctl restart networking\n```\n\nAt the beginning, you need a virtual interface TAP:\n```sh\n# ip tuntap add mode tap tap100\n# ip link set dev tap100 up\n# brctl addif br0 tap100\n```\n\nIn such layout, you need to \"redirect\" TCP/IP packets from eht0:443 to your\nprivate IP address 10.0.0.2 (your unikernel). It's possible to do that via\n`iptables`:\n```sh\n$ sysctl -w net.ipv4.ip_forward=1\n$ iptables -A FORWARD -o br0 -m conntrack --ctstate RELATED,ESTABLISHED \\\n  -j ACCEPT\n$ iptables -A FORWARD -i br0 ! -o br0 -j ACCEPT\n$ iptables -A FORWARD -i br0 -o br0 -j ACCEPT\n$ iptables -t nat -A POSTROUTING -s 10.0.0.0/24 ! -o eth0 -j MASQUERADE\n$ iptables -N CONTRUNO\n$ iptables -A CONTRUNO -d 10.0.0.2/32 ! -i br0 -o br0 \\\n  -p tcp -m tcp --dport 80 -j ACCEPT\n$ iptables -A CONTRUNO -d 10.0.0.2/32 ! -i br0 -o br0 \\\n  -p tcp -m tcp --dport 443 -j ACCEPT\n$ iptables -A FORWARD -o br0 -j CONTRUNO\n$ iptables -t nat -A PREROUTING -m addrytpe --dst-type LOCAL -j CONTRUNO\n$ iptables -t nat -A CONTRUNO ! -s 10.0.0.2/32 -p tcp -m tcp --dport 443 \\\n  -j DNAT --to-destination 10.0.0.2:443\n$ iptables -t nat -A CONTRUNO ! -s 10.0.0.2/32 -p tcp -m tcp --dport 80 \\\n  -j DNAT --to-destination 10.0.0.2:80\n```\n\n#### How to make a simple Git repository?\n\n`contruno` needs a Git repository to store certificates for each domains. It's\neasy to create a private Git repository and, in our context, it's perfect.\nIndeed, the Git repository will contains private keys, so it should only be\naccessible on your private network.\n\nWe will create our own Git repository with a specific SSH public key generated\nby `awa_gen_key`:\n```sh\n$ awa_gen_key \u003e awa.gen.key\n$ cat awa.gen.key | head -n1\nseed is U01hpCOJ/MHLri7YBi7NBXqZ8TXDkVyXSb7CdGQr\n# adduser git\n# su git\n$ cd\n$ mkdir .ssh \u0026\u0026 chmod 700 .ssh\n$ touch .ssh/authorized_keys \u0026\u0026 chmod 600 .ssh/authorized_keys\n$ cat awa.gen.key | tail -n1 \u003e\u003e .ssh/authorized_keys\n$ mkdir certificates.git\n$ cd certificates.git\n$ git init --bare\n$ FIRST_COMMIT=`git commit-tree $(git write-tree) -m .`\n$ git update-ref \"refs/heads/master\" $FIRST_COMMIT\n```\n\nSo we just make a Git repository with one commit. Into the\n`.ssh/authorized_keys`, you should put your SSH public key to be able to pull\nand push on this local repository. The seed generated by `awa_gen_key` is\nimportant. We will pass it to the unikernel to be able to reconstruct the SSH\nprivate key then (and let the unikernel to `pull`/`push`).\n\nNow, we can deploy our unikernel. At this stage, we need to keep our unikernel\nalive. The usual way to do that is to use `screen` (or to _daemonize_ the\nprocess). By this way, the unikernel still continue to run even if we are\ndisconnected. Then, we need to have an access to `kvm`, so the current user\nneeds to be a part of the `kvm` group. Finally, we will use `solo5-hvt` has our\ntender to launch our unikernel:\n```sh\n$ usermod -aG kvm $USER\n$ screen\n$ solo5-hvt --net:service=tap100 contruno.hvt -- \\\n  --ipv4=10.0.0.2/24 \\\n  --ipv4-gateway=10.0.0.1 \\\n  --remote git@10.0.0.1:certificates.git#master \\\n  --pass foo \\\n  --production false \\\n  --ssh-ssh U01hpCOJ/MHLri7YBi7NBXqZ8TXDkVyXSb7CdGQr \\\n```\n\n**NOTE**: We currently launched `contruno` with `--production false` which\nmeans that `contruno` will ask only fake certificates to let's encrypt. If you\nreally want to deploy `contruno` and use it, you should set the option to\n`true`. We use the `false` option to let you to test `contruno` without\nlimitations from let's encrypt (you can ask an re-ask certificates without\nbeing banned).\n\nFinally, we can ask a new certificate via our `contruno.add` tool:\n```sh\n$ contruno.add --hostname \u003cyour-hostname\u003e --ip \u003cprivate-ip-of-your-website\u003e \\\n  --pass foo -r git@localhost:certificates.git#master \\\n  --target 10.0.0.2\n```\n\nThe last command will create a fake and expired certificate which enforces\n`contruno` to re-asking a new one and update the `certificates.git` Git\nrepository with the new one. Then, `contruno` will use it for any HTTP\nrequests to `\u003cyour-hostname\u003e`.\n\nAnd, voilà!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdinosaure%2Fcontruno","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdinosaure%2Fcontruno","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdinosaure%2Fcontruno/lists"}