+Nebula is a scalable overlay networking tool with a focus on performance, simplicity and security.
+It lets you seamlessly connect computers anywhere in the world. Nebula is portable, and runs on Linux, OSX, and Windows.
+(Also: keep this quiet, but we have an early prototype running on iOS).
+It can be used to connect a small number of computers, but is also able to connect tens of thousands of computers.
+
+Nebula incorporates a number of existing concepts like encryption, security groups, certificates,
+and tunneling, and each of those individual pieces existed before Nebula in various forms.
+What makes Nebula different to existing offerings is that it brings all of these ideas together,
+resulting in a sum that is greater than its individual parts.
+
+You can read more about Nebula [here](https://medium.com/p/884110a5579).
+
+## Technical Overview
+
+Nebula is a mutually authenticated peer-to-peer software defined network based on the [Noise Protocol Framework](https://noiseprotocol.org/).
+Nebula uses certificates to assert a node's IP address, name, and membership within user-defined groups.
+Nebula's user-defined groups allow for provider agnostic traffic filtering between nodes.
+Discovery nodes allow individual peers to find each other and optionally use UDP hole punching to establish connections from behind most firewalls or NATs.
+Users can move data between nodes in any number of cloud service providers, datacenters, and endpoints, without needing to maintain a particular addressing scheme.
+
+Nebula uses elliptic curve Diffie-Hellman key exchange, and AES-256-GCM in its default configuration.
+
+Nebula was created to provide a mechanism for groups hosts to communicate securely, even across the internet, while enabling expressive firewall definitions similar in style to cloud security groups.
+
+## Getting started (quickly)
+
+To set up a Nebula network, you'll need:
+
+#### 1. The [Nebula binaries](https://github.com/slackhq/nebula/releases) for your specific platform. Specifically you'll need `nebula-cert` and the specific nebula binary for each platform you use.
+
+#### 2. (Optional, but you really should..) At least one discovery node with a routable IP address, which we call a lighthouse.
+
+Nebula lighthouses allow nodes to find each other, anywhere in the world. A lighthouse is the only node in a Nebula network whose IP should not change. Running a lighthouse requires very few compute resources, and you can easily use the least expensive option from a cloud hosting provider. If you're not sure which provider to use, a number of us have used $5/mo [DigitalOcean](https://digitalocean.com) droplets as lighthouses.
+
+ Once you have launched an instance, ensure that Nebula udp traffic (default port udp/4242) can reach it over the internet.
+
+
+#### 3. A Nebula certificate authority, which will be the root of trust for a particular Nebula network.
+
+ ```
+ ./nebula-cert ca -name "Myorganization, Inc"
+ ```
+ This will create files named `ca.key` and `ca.cert` in the current directory. The `ca.key` file is the most sensitive file you'll create, because it is the key used to sign the certificates for individual nebula nodes/hosts. Please store this file somewhere safe, preferably with strong encryption.
+
+#### 4. Nebula host keys and certificates generated from that certificate authority
+This assumes you have three nodes, named lighthouse1, host1, host3. You can name the nodes any way you'd like, including FQDN. You'll also need to choose IP addresses and the associated subnet. In this example, we are creating a nebula network that will use 192.168.100.x/24 as its network range. This example also demonstrates nebula groups, which can later be used to define traffic rules in a nebula network.
+Download a copy of the nebula [example configuration](https://github.com/slackhq/nebula/blob/master/examples/config.yaml).
+
+* On the lighthouse node, you'll need to ensure `am_lighthouse: true` is set.
+
+* On the individual hosts, ensure the lighthouse is defined properly in the `static_host_map` section, and is added to the lighthouse `hosts` section.
+
+
+#### 6. Copy nebula credentials, configuration, and binaries to each host
+
+For each host, copy the nebula binary to the host, along with `config.yaml` from step 5, and the files `ca.crt`, `{host}.crt`, and `{host}.key` from step 2.
+
+**DO NOT COPY `ca.key` TO INDIVIDUAL NODES.**
+
+#### 7. Run nebula on each host
+```
+./nebula -config /path/to/config.yaml
+```
+
+## Building Nebula from source
+
+Download go and clone this repo. Change to the nebula directory.
+
+To build nebula for all platforms:
+`make all`
+
+To build nebula for a specific platform (ex, Windows):
+`make bin-windows`
+
+See the [Makefile](Makefile) for more details on build targets
+
+## Credits
+
+Nebula was created at Slack Technologies, Inc by Nate Brown and Ryan Huber, with contributions from Oliver Fross, Alan Lam, Wade Simmons, and Lining Wang.
+ if i > b.current || (i == 0 && b.firstSeen == false && b.current < b.length) {
+ return true
+ }
+
+ // If i is within the window, check if it's been set already. The first window will fail this check
+ if i > b.current-b.length {
+ return !b.bits[i%b.length]
+ }
+
+ // If i is within the first window
+ if i < b.length {
+ return !b.bits[i%b.length]
+ }
+
+ // Not within the window
+ l.Debugf("rejected a packet (top) %d %d\n", b.current, i)
+ return false
+}
+
+func (b *Bits) Update(i uint64) bool {
+ // If i is the next number, return true and update current.
+ if i == b.current+1 {
+ // Report missed packets, we can only understand what was missed after the first window has been gone through
+ if i > b.length && b.bits[i%b.length] == false {
+ b.lostCounter.Inc(1)
+ }
+ b.bits[i%b.length] = true
+ b.current = i
+ return true
+ }
+
+ // If i packet is greater than current but less than the maximum length of our bitmap,
+ // flip everything in between to false and move ahead.
+ if i > b.current && i < b.current+b.length {
+ // In between current and i need to be zero'd to allow those packets to come in later
+ for n := b.current + 1; n < i; n++ {
+ b.bits[n%b.length] = false
+ }
+
+ b.bits[i%b.length] = true
+ b.current = i
+ //l.Debugf("missed %d packets between %d and %d\n", i-b.current, i, b.current)
+ return true
+ }
+
+ // If i is greater than the delta between current and the total length of our bitmap,
+ // just flip everything in the map and move ahead.
+ if i >= b.current+b.length {
+ // The current window loss will be accounted for later, only record the jump as loss up until then
+ lost := maxInt64(0, int64(i-b.current-b.length))
+ //TODO: explain this
+ if b.current == 0 {
+ lost++
+ }
+
+ for n := range b.bits {
+ // Don't want to count the first window as a loss
+ //TODO: this is likely wrong, we are wanting to track only the bit slots that we aren't going to track anymore and this is marking everything as missed
+ cf.name = cf.set.String("name", "", "Required: name of the certificate authority")
+ cf.duration = cf.set.Duration("duration", time.Duration(time.Hour*8760), "Optional: amount of time the certificate should be valid for. Valid time units are seconds: \"s\", minutes: \"m\", hours: \"h\"")
+ cf.outKeyPath = cf.set.String("out-key", "ca.key", "Optional: path to write the private key to")
+ cf.outCertPath = cf.set.String("out-crt", "ca.crt", "Optional: path to write the certificate to")
+ cf.groups = cf.set.String("groups", "", "Optional: comma separated list of groups. This will limit which groups subordinate certs can use")
+ return &cf
+}
+
+func ca(args []string, out io.Writer, errOut io.Writer) error {
+ cf := newCaFlags()
+ err := cf.set.Parse(args)
+ if err != nil {
+ return err
+ }
+
+ if err := mustFlagString("name", cf.name); err != nil {
+ return err
+ }
+ if err := mustFlagString("out-key", cf.outKeyPath); err != nil {
+ return err
+ }
+ if err := mustFlagString("out-crt", cf.outCertPath); err != nil {
+ return err
+ }
+
+ if *cf.duration <= 0 {
+ return &helpError{"-duration must be greater than 0"}
+ }
+
+ groups := []string{}
+ if *cf.groups != "" {
+ for _, rg := range strings.Split(*cf.groups, ",") {
+ assert.Equal(t, "ca <flags>: create a self signed certificate authority", caSummary())
+}
+
+func Test_caHelp(t *testing.T) {
+ ob := &bytes.Buffer{}
+ caHelp(ob)
+ assert.Equal(
+ t,
+ "Usage of "+os.Args[0]+" ca <flags>: create a self signed certificate authority\n"+
+ " -duration duration\n"+
+ " \tOptional: amount of time the certificate should be valid for. Valid time units are seconds: \"s\", minutes: \"m\", hours: \"h\" (default 8760h0m0s)\n"+
+ " -groups string\n"+
+ " \tOptional: comma separated list of groups. This will limit which groups subordinate certs can use\n"+
+ " -name string\n"+
+ " \tRequired: name of the certificate authority\n"+
+ " -out-crt string\n"+
+ " \tOptional: path to write the certificate to (default \"ca.crt\")\n"+
+ " -out-key string\n"+
+ " \tOptional: path to write the private key to (default \"ca.key\")\n",
+ sf := signFlags{set: flag.NewFlagSet("sign", flag.ContinueOnError)}
+ sf.set.Usage = func() {}
+ sf.caKeyPath = sf.set.String("ca-key", "ca.key", "Optional: path to the signing CA key")
+ sf.caCertPath = sf.set.String("ca-crt", "ca.crt", "Optional: path to the signing CA cert")
+ sf.name = sf.set.String("name", "", "Required: name of the cert, usually a hostname")
+ sf.ip = sf.set.String("ip", "", "Required: ip and network in CIDR notation to assign the cert")
+ sf.duration = sf.set.Duration("duration", 0, "Required: how long the cert should be valid for. Valid time units are seconds: \"s\", minutes: \"m\", hours: \"h\"")
+ sf.inPubPath = sf.set.String("in-pub", "", "Optional (if out-key not set): path to read a previously generated public key")
+ sf.outKeyPath = sf.set.String("out-key", "", "Optional (if in-pub not set): path to write the private key to")
+ sf.outCertPath = sf.set.String("out-crt", "", "Optional: path to write the certificate to")
+ sf.groups = sf.set.String("groups", "", "Optional: comma separated list of groups")
+ sf.subnets = sf.set.String("subnets", "", "Optional: comma seperated list of subnet this cert can serve for")
+ return &sf
+
+}
+
+func signCert(args []string, out io.Writer, errOut io.Writer) error {
+ sf := newSignFlags()
+ err := sf.set.Parse(args)
+ if err != nil {
+ return err
+ }
+
+ if err := mustFlagString("ca-key", sf.caKeyPath); err != nil {
+ return err
+ }
+ if err := mustFlagString("ca-crt", sf.caCertPath); err != nil {
+ return err
+ }
+ if err := mustFlagString("name", sf.name); err != nil {
+ return err
+ }
+ if err := mustFlagString("ip", sf.ip); err != nil {
+ return err
+ }
+ if *sf.inPubPath != "" && *sf.outKeyPath != "" {
+ return newHelpErrorf("cannot set both -in-pub and -out-key")
+ }
+
+ rawCAKey, err := ioutil.ReadFile(*sf.caKeyPath)
+ if err != nil {
+ return fmt.Errorf("error while reading ca-key: %s", err)
+# Example, if your lighthouse has the nebula IP of 192.168.100.1 and has the real ip address of 100.64.22.11 and runs on port 4242:
+static_host_map:
+ "192.168.100.1": ["100.64.22.11:4242"]
+
+
+lighthouse:
+ # am_lighthouse is used to enable lighthouse functionality for a node. This should ONLY be true on nodes
+ # you have configured to be lighthouses in your network
+ am_lighthouse: false
+ # serve_dns optionally starts a dns listener that responds to various queries and can even be
+ # delegated to for resolution
+ #serve_dns: false
+ # interval is the number of seconds between updates from this node to a lighthouse.
+ # during updates, a node sends information about its current IP addresses to each node.
+ interval: 60
+ # hosts is a list of lighthouse hosts this node should report to and query from
+ # IMPORTANT: THIS SHOULD BE EMPTY ON LIGHTHOUSE NODES
+ hosts:
+ - "192.168.100.1"
+
+# Port Nebula will be listening on. The default here is 4242. For a lighthouse node, the port should be defined,
+# however using port 0 will dynamically assign a port and is recommended for roaming nodes.
+listen:
+ host: 0.0.0.0
+ port: 4242
+ # Sets the max number of packets to pull from the kernel for each syscall (under systems that support recvmmsg)
+ # default is 64, does not support reload
+ #batch: 64
+ # Configure socket buffers for the udp side (outside), leave unset to use the system defaults. Values will be doubled by the kernel
+ # Default is net.core.rmem_default and net.core.wmem_default (/proc/sys/net/core/rmem_default and /proc/sys/net/core/rmem_default)
+ # Maximum is limited by memory in the system, SO_RCVBUFFORCE and SO_SNDBUFFORCE is used to avoid having to raise the system wide
+ # max, net.core.rmem_max and net.core.wmem_max
+ #read_buffer: 10485760
+ #write_buffer: 10485760
+
+
+# Local range is used to define a hint about the local network range, which speeds up discovering the fastest
+# path to a network adjacent nebula node.
+#local_range: "172.16.0.0/24"
+
+# Handshake mac is an optional network-wide handshake authentication step that is used to prevent nebula from
+# responding to handshakes from nodes not in possession of the shared secret. This is primarily used to prevent
+# detection of nebula nodes when someone is scanning a network.
+#handshake_mac:
+ #key: "DONOTUSETHISKEY"
+ # You can define multiple accepted keys
+ #accepted_keys:
+ #- "DONOTUSETHISKEY"
+ #- "dontusethiseither"
+
+# sshd can expose informational and administrative functions via ssh this is a
+#sshd:
+ # Toggles the feature
+ #enabled: true
+ # Host and port to listen on, port 22 is not allowed for your safety
+ #listen: 127.0.0.1:2222
+ # A file containing the ssh host private key to use
+ # A decent way to generate one: ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" < /dev/null
+ #host_key: ./ssh_host_ed25519_key
+ # A file containing a list of authorized public keys
+ #authorized_users:
+ #- user: steeeeve
+ # keys can be an array of strings or single string
+ #keys:
+ #- "ssh public key string"
+
+# Configure the private interface. Note: addr is baked into the nebula certificate
+tun:
+ # Name of the device
+ dev: nebula1
+ # Toggles forwarding of local broadcast packets, the address of which depends on the ip/mask encoded in pki.cert
+ drop_local_broadcast: false
+ # Toggles forwarding of multicast packets
+ drop_multicast: false
+ # Sets the transmit queue length, if you notice lots of transmit drops on the tun it may help to raise this number. Default is 500
+ tx_queue: 500
+ # Default MTU for every packet, safe setting is (and the default) 1300 for internet based traffic
+ mtu: 1300
+ # Route based MTU overrides, you have known vpn ip paths that can support larger MTUs you can increase/decrease them here
+ routes:
+ #- mtu: 8800
+ # route: 10.0.0.0/16
+
+# TODO
+# Configure logging level
+logging:
+ # panic, fatal, error, warning, info, or debug. Default is info
+ level: info
+ # json or text formats currently available. Default is text
+ format: text
+
+#stats:
+ #type: graphite
+ #prefix: nebula
+ #protocol: tcp
+ #host: 127.0.0.1:9999
+ #interval: 10s
+
+ #type: prometheus
+ #listen: 127.0.0.1:8080
+ #path: /metrics
+ #namespace: prometheusns
+ #subsystem: nebula
+ #interval: 10s
+
+# Nebula security group configuration
+firewall:
+ conntrack:
+ tcp_timeout: 120h
+ udp_timeout: 3m
+ default_timeout: 10m
+ max_connections: 100000
+
+ # The firewall is default deny. There is no way to write a deny rule.
+ # Rules are comprised of a protocol, port, and one or more of host, group, or CIDR
+ # Logical evaluation is roughly: port AND proto AND ca_sha AND ca_name AND (host OR group OR groups OR cidr)
+ # - port: Takes `0` or `any` as any, a single number `80`, a range `200-901`, or `fragment` to match second and further fragments of fragmented packets (since there is no port available).
+ # code: same as port but makes more sense when talking about ICMP, TODO: this is not currently implemented in a way that works, use `any`
+ # proto: `any`, `tcp`, `udp`, or `icmp`
+ # host: `any` or a literal hostname, ie `test-host`
+ # group: `any` or a literal group name, ie `default-group`
+ # groups: Same as group but accepts a list of values. Multiple values are AND'd together and a certificate would have to contain all groups to pass
+ # cidr: a CIDR, `0.0.0.0/0` is any.
+ # ca_name: An issuing CA name
+ # ca_sha: An issuing CA shasum
+
+ outbound:
+ # Allow all outbound traffic from this node
+ - port: any
+ proto: any
+ host: any
+
+ inbound:
+ # Allow icmp between any nebula hosts
+ - port: any
+ proto: icmp
+ host: any
+
+ # Allow tcp/443 from any host with BOTH laptop and home group
+Are you able to ping other boxes on the private nebula network?
+
+The following are the private nebula ip addresses of the vagrant env
+
+```
+generic1.vagrant [nebula_ip] 10.168.91.210
+generic2.vagrant [nebula_ip] 10.168.91.220
+lighthouse1.vagrant [nebula_ip] 10.168.91.230
+```
+
+Try pinging generic1.vagrant to and from any other box using its nebula ip above.
+
+Double check the nebula firewall rules under /etc/nebula/config.yml to make sure that connectivity is allowed for your use-case if on a specific port.
+ assert.EqualError(t, err, "entry 1.route in tun.routes is not contained within the network attached to the certificate; route: 1.0.0.0/8, network: 10.0.0.0/24")
+ assert.EqualError(t, err, "entry 1.route in tun.routes is not contained within the network attached to the certificate; route: 10.0.1.0/24, network: 10.0.0.0/24")