{"id":41051,"date":"2020-02-05T21:28:58","date_gmt":"2020-02-05T18:28:58","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/consul-iptables-3"},"modified":"2020-02-05T21:28:58","modified_gmt":"2020-02-05T18:28:58","slug":"consul-iptables-3","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/consul-iptables-3","title":{"rendered":"Consul + iptables = :3","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>In 2010, the company <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/wargaming\/\">Wargaming<\/a><\/noindex> had 50 servers and a simple network model: backend, frontend, and firewall. The number of servers grew, the model became more complex: staging, isolated VLANs with ACLs, then VPNs with VRFs, VLANs with ACLs on L2, VRFs with ACLs on L3. Feeling overwhelmed? It gets more interesting.<\/p>\n<p>When the number of servers reached 16,000, it became impossible to work without tears with such a diverse array of segments. So, another solution was devised. They took the Netfilter stack, added Consul as a data source, resulting in a fast distributed firewall. This replaced ACLs on routers and was used as both an external and internal firewall. To dynamically manage the tool, they developed the BEFW system, which was applied everywhere: from managing user access in the product network to isolating network segments from one another.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/246e74278f413749a676599b5ce986a5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nHow all this works and why you should take a closer look at this system will be explained by <strong>Ivan Agarkov<\/strong> (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/annmuor\/\" class=\"user_link\">annmuor<\/a><\/noindex>) \u2014 head of the infrastructure security group in the Maintenance division at the Minsk development center of the company. Ivan is a fan of SELinux, loves Perl, and writes code. As the head of the security group, he regularly works with logs, backups, and R&amp;D to protect Wargaming from hackers and ensure the operation of all gaming servers in the company.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\n<center><div class=\"youtube-placeholder\" data-id=\"4zP67uYnsR4\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/4zP67uYnsR4\/hqdefault.jpg\" alt=\"Play video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><\/p>\n<h2>Historical Background<\/h2>\n<p>\nBefore explaining how we did this, I will recount how we got here in the first place and why this was necessary. To do this, let\u2019s go back 9 years: 2010, when World of Tanks had just launched. Wargaming had about 50 servers.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/64e1c2839363dbdf59ba5f11bb13530e.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>The growth chart of the company\u2019s servers.<\/em><\/p>\n<p>We had a network model. For that time, it was optimal.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/c0509324e2a83882a9792ba75612ceea.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>The network model in 2010.<\/em><\/p>\n<p>The bad guys who want to break us live on the frontend, but there\u2019s a firewall in place. There\u2019s no firewall on the backend, but there are 50 servers, and we know all of them. Everything works well.<\/p>\n<p>Within 4 years, the server park grew 100 times, to 5,000. The first isolated networks appeared \u2014 staging: they cannot access production, and they often ran potentially dangerous content.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/08e1d7670ce1a1346e49d87c67c4be1b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>The network model in 2014.<\/em><\/p>\n<p>By inertia, we continued to use the same hardware, and all work was conducted on isolated VLANs: ACLs were written to the VLANs that allow or deny certain connections.<\/p>\n<p>In 2016, the number of servers reached 8,000. Wargaming acquired other studios, and additional partner networks emerged. They seem to be ours, but not quite: the VLAN often doesn\u2019t work for partners, requiring the use of VPNs with VRF, complicating isolations. The mix of ACL isolations grew.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/a6580c9551730447e16d7881eb102275.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>The network model in 2016.<\/em><\/p>\n<p>By early 2018, the fleet had grown to 16,000 machines. There were 6 segments, and we didn't count the others, including those holding financial data. Container networks (Kubernetes), DevOps, and cloud networks connected via VPN, like from IVS, appeared. There were too many rules\u2014it was painful.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/ec44e6a60da98daa4bbf2bca2e3b2e1a.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<em>The network model and isolation methods in 2018.<\/em><\/p>\n<p>For isolation, we used: VLANs with ACLs at L2, VRF with ACLs at L3, VPNs, and much more. Too much.<\/p>\n<h2>Issues<\/h2>\n<p>\nEveryone operates with ACLs and VLANs. What\u2019s the problem? Harold, hiding the pain, will answer this question.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/4df5105af3bce515d80e8e5f3e14c027.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThere were many issues, but only five were widespread.<\/p>\n<ul>\n<li><strong>Exponential price increase for new rules.<\/strong>. Each new rule took longer to add than the previous one since we needed to check if such a rule already existed.<\/li>\n<li><strong>No firewall within the segments.<\/strong>. The segments were somehow separated from each other, but internally resources were lacking.<\/li>\n<li><strong>Rules were applied slowly. <\/strong>Operators could write one local rule by hand in an hour. Global rules took several days.<\/li>\n<li><strong>Challenges with rule auditing.<\/strong>. More precisely, it was impossible. The first rules were written back in 2010, and most of their authors no longer worked at the company.<\/li>\n<li><strong>Low level of control over the infrastructure.<\/strong>. This is the main issue\u2014we poorly understood what was really happening.<\/li>\n<\/ul>\n<p>\nThis is what a network engineer looked like in 2018 when he heard: 'We need a bit more ACL.'<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/8366d3092558ebb15a4ba6d8e5702032.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Solutions<\/h2>\n<p>\nAt the beginning of 2018, it was decided that something needed to be done about this.<\/p>\n<p><strong>The cost of integrations is continuously rising. <\/strong>The starting point was that large data centers stopped supporting isolated VLANs and ACLs because the devices ran out of memory.<\/p>\n<p>Solution: eliminate the human factor and automate access provision to the maximum.<\/p>\n<p><strong>New rules take a long time to be applied. <\/strong>Solution: accelerate rule application, making it distributed and parallel. A distributed system is needed for rules to be delivered autonomously, without rsync or SFTP to a thousand systems.<\/p>\n<p><strong>Absence of a firewall within segments. <\/strong>Firewalls within segments started affecting us when different services emerged within a single network. Solution: use host-based firewalls. Almost everywhere we have Linux, and iptables is available, so it\u2019s not an issue.<\/p>\n<p><strong>Challenges with auditing rules.<\/strong> Solution: store all rules in one place for review and management, enabling us to audit everything.<\/p>\n<p><strong>Low level of infrastructure control. <\/strong>Solution: conduct an inventory of all services and the accesses between them.<\/p>\n<p>This is more of an administrative process than a technical one. Sometimes we have 200-300 new releases a week, particularly during promotions and holidays. This is just for one of our DevOps teams. With that many releases, it's impossible to know which ports, IPs, and integrations are required. Therefore, we needed specially trained service managers to interview the teams: 'What is out there and why did you deploy this?'<\/p>\n<p>After everything we launched, the network engineer looked like this in 2019.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/ccca25d7f7bb7f70638725addc6d99ed.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Consul<\/h2>\n<p>\nWe decided that everything we discovered with the help of service managers would be placed in Consul, from which we would write iptables rules.<\/p>\n<p>How did we decide to do this?<\/p>\n<ul>\n<li>We will gather all services, networks, and users.<\/li>\n<li>We will create iptables rules based on them.<\/li>\n<li>We will automate control.<\/li>\n<li>\u2026.<\/li>\n<li>PROFIT.<\/li>\n<\/ul>\n<p>\nConsul is not a remote API; it can operate on each node and write to iptables. We just need to devise automated control tools that will clean up the extras, and most of the problems will be resolved! The rest we will refine in the process.<\/p>\n<h3>Why Consul?<\/h3>\n<p>\n<strong>It has proven itself well. <\/strong>In 2014-2015, we used it as a backend for Vault, where we store passwords.<\/p>\n<p><strong>Does not lose data.<\/strong>. Throughout the usage of Consul, it has not lost data during any incidents. This is a huge plus for the firewall management system.<\/p>\n<p><strong>P2P connections accelerate the dissemination of changes.<\/strong>. With P2P, all changes arrive quickly, no need to wait for hours.<\/p>\n<p><strong>Convenient REST API.<\/strong> We also considered Apache ZooKeeper, but it lacks a REST API, so we would need to add workarounds.<\/p>\n<p><strong>Works as both a key-value store (KV) and a directory (Service Discovery).<\/strong>. You can store services, catalogs, and data centers at once. This is convenient not only for us but also for adjacent teams, as we think on a large scale when building a global service.<\/p>\n<p><strong>Written in Go, which is part of the Wargaming tech stack. <\/strong>We love this language; we have many Go developers.<\/p>\n<p><strong>Powerful ACL system. <\/strong>In Consul, ACL can control who can write and to what. We ensure that the firewall rules will not overlap with anything else, and we won't have issues with that.<\/p>\n<p>However, Consul has its drawbacks.<\/p>\n<ul>\n<li><strong>It doesn\u2019t scale within a data center unless you have the business version. <\/strong>It only scales through federation.<\/li>\n<li><strong>It is highly dependent on network quality and server load. <\/strong>Consul will not function properly as a server on a busy server if there are any lags in the network, for example, unstable speeds. This is related to P2P connections and update propagation models.<\/li>\n<li><strong>Challenges with availability monitoring<\/strong>. The status of Consul might indicate that everything is fine while it has actually crashed a long time ago.<\/li>\n<\/ul>\n<p>\nMost of these problems were resolved during the operation of Consul, which is why we chose it. The company has plans for an alternative backend, but we have learned to tackle the issues and are currently living with Consul.<\/p>\n<h3>How Consul works<\/h3>\n<p>\nIn a hypothetical data center, we will set up servers \u2014 from three to five. One or two servers will not suffice: they will not be able to establish quorum and determine who is right when data does not match. More than five is pointless, as performance will decline.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/96153c4e9075b067b34a63ceba5b80f0.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nClients connect to the servers in any order: the same agents, just with the flag <code>server = false<\/code>.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/0854d1286c18bb5e7c1130c6734154a9.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAfter that, clients receive a list of P2P connections and establish relationships between themselves.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/2457cb7707c27cc23f6e13415119b91d.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAt a global level, we connect several data centers together. They are also connected via P2P and communicate.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/3b4ae922eb8d2a6a9a79425e769505d7.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWhen we want to retrieve data from another data center, the request goes from server to server. This is called <strong>the Serf protocol<\/strong>. The Serf protocol, like Consul, was developed by HashiCorp.<\/p>\n<h3>Several important facts about Consul<\/h3>\n<p>\nConsul has documentation describing its operation. I will provide only selected facts that are worth knowing.<\/p>\n<p><strong>Consul servers elect a master from among the voters<\/strong>. Consul selects a master from the list of servers for each data center, and all requests go only to it, regardless of the number of servers. If the master hangs, it does not lead to re-elections. If no master is elected, requests are served by no one.<\/p>\n<blockquote><p>Did you want horizontal scaling? Sorry, no.<\/p><\/blockquote>\n<p> The request to another data center goes from master to master, regardless of which server it came to. The selected master receives 100% of the load, except for the load on forwarding requests. An updated copy of the data is available on all servers in the data center, but only one responds.<\/p>\n<blockquote><p>The only way to scale is to enable stale mode on the client.<\/p><\/blockquote>\n<p>In stale mode, responses can be given without quorum. This is a mode in which we give up on data consistency but read slightly faster than usual, and any server can respond. Naturally, writes can only go through the master.<\/p>\n<p><strong>Consul does not replicate data between data centers<\/strong>. When gathering federations, each server will only have its own data. For others, it will always refer to someone else.<\/p>\n<p><strong>Atomicity of operations is not guaranteed outside of transactions<\/strong>. Remember that changes can be made not only by you. If you want to do it differently, conduct a transaction with locking.<\/p>\n<p><strong>Blocking operations do not guarantee locking<\/strong>. The request goes from master to master, not directly, so there are no guarantees that the lock will work when you try to apply a lock, for example, in another data center.<\/p>\n<p><strong>ACL also does not guarantee access (in many cases)<\/strong>. ACL may fail, as it is stored in one data center of the federation \u2014 in the ACL data center (Primary DC). If the DC does not respond, the ACL will not work.<\/p>\n<p><strong>One hung master will lead to the hanging of the entire federation<\/strong>. For example, in a federation of 10 data centers, if one has poor network connectivity and one master crashes, everyone communicating with it will hang in a loop: a request is made, there is no response, the thread hangs. It won't be possible to know when this will happen; in an hour or two, the entire federation will crash. There is nothing you can do about it.<\/p>\n<p>Status, quorum, and elections are handled by a separate thread. Re-elections won\u2019t happen, the status will show nothing. You think you have a live Consul, you request it, and nothing happens \u2014 there\u2019s no response. Meanwhile, the status indicates everything is fine.<\/p>\n<p>We have encountered this problem, and we had to rebuild specific parts of the data centers to avoid it.<\/p>\n<p><strong>In the business version of Consul Enterprise, some of the above drawbacks are absent<\/strong>It has many useful features: voter selection, distribution, scaling. There's just one catch \u2014 the licensing system for a distributed setup is very expensive.<\/p>\n<p>Life hack: <code>rm -rf \/var\/lib\/consul<\/code> \u2014 a cure for all the agent's ailments. If something isn't working, just delete your data and load it from a backup. Most likely, Consul will start working again.<\/p>\n<h2>BEFW<\/h2>\n<p>\nNow, let's talk about what we've added to Consul.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wgnet\/befw\">BEFW<\/a><\/noindex> \u2014 it's an acronym for <strong>B<\/strong>ack<strong>E<\/strong>nd<strong>F<\/strong>ire<strong>W<\/strong>all. I had to come up with a name for the product when I created the repository to store the first test commits. That name stuck.<\/p>\n<h3>Rule templates<\/h3>\n<p>\nThe rules are written in iptables syntax.<\/p>\n<ul>\n<li>-N BEFW<\/li>\n<li>-P INPUT DROP<\/li>\n<li>-A INPUT -m state--state RELATED,ESTABLISHED -j ACCEPT<\/li>\n<li>-A INPUT -i lo -j ACCEPT<\/li>\n<li>-A INPUT -j BEFW<\/li>\n<\/ul>\n<p>\nEverything flows into the BEFW chain, except for <code>ESTABLISHED<\/code>, <code>RELATED<\/code> and localhost. The template can be anything; this is just an example.<\/p>\n<p>What is the benefit of BEFW?<\/p>\n<h3>Services<\/h3>\n<p>\nWe have a service, it always has a port, and the node on which it runs. From our node, we can locally query the agent and find out we have some service. We can also assign tags.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/6d8c74db37e2e1eed971cfa6947cc5c8.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAny service that is running and registered in Consul becomes an iptables rule. We have SSH \u2014 let's open port 22. The bash script is simple: curl and iptables, nothing more is needed.<\/p>\n<h3>Clients<\/h3>\n<p>\nHow to grant access selectively, not to everyone? Store IP lists in the KV store by service name.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/11a5af5aad9e848565458f168a1eee64.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nFor example, we want everyone from the tenth network to be able to access the SSH_TCP_22 service. We add a small TTL field? and now we have temporary permissions, for example, for a day.<\/p>\n<h3>Accesses<\/h3>\n<p>\nConnecting services and clients: we have a service with a KV store ready for each. Now we grant access selectively, not to everyone.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/d1119fbb226595184cac8d9ce7a924e3.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Groups<\/h3>\n<p>\nIf we keep writing thousands of IPs for access, we'll get tired. Let's think of groupings \u2014 a separate subset in the KV. We'll call it Alias (or groups) and store those groups there following the same principle.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/67c6ab76cc25a3973739bdd44b69cef9.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nConnecting: now we can open SSH not specifically on P2P, but to an entire group or several groups. Similarly, there\u2019s TTL \u2014 we can add to or remove from the group temporarily.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/a00b7db5087a96730c2725090f33e2b0.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Integration<\/h3>\n<p>\nOur problem is the human factor and automation. For now, we have solved it this way.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/ce7a0c16543d0624453e6bdada3b8f03.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe work with Puppet and transfer everything related to the system (application code) to it. In puppetdb (a standard PostgreSQL), there is a list of services that are running there, which can be found by resource type. You can also see who is accessing what. Additionally, we have a pull request and merge request system for this.<\/p>\n<p>We created befw-sync\u2014 the simplest solution that helps transfer data. First, sync cookies query puppetdb. There, an HTTP API is set up: we request what services we have and what needs to be done. Then, it makes a request to Consul.<\/p>\n<p>Is there integration? Yes: we wrote rules, allowed Pull Requests. Is a port needed or adding a host to a group? Pull Request, review\u2014no more 'Find 200 other ACLs and try to do something with this.'<\/p>\n<h3>Optimization<\/h3>\n<p>\nPinging localhost with an empty chain of rules takes 0.075 ms.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/39263844f79c4795af05dc3ecb734394.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe will add 10,000 addresses to iptables in this chain. As a result, ping will increase 5 times: iptables is completely linear, processing each address takes some time.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/e6c314155c3a34fdf61e40479ecb26c3.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nFor the firewall to which we are migrating thousands of ACLs, we have many rules, which causes delays. This is bad for gaming protocols.<\/p>\n<p>But if we place <strong>10,000 addresses in ipset<\/strong> ping will even decrease.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/2dd844d9324d057ba9ab098e501a1e51.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThe point is that 'O' (algorithm complexity) for ipset is always 1, no matter how many rules there are. However, there is a limitation\u2014there cannot be more than 65,535 rules. For now, we live with this: we can combine them, expand, and make two ipsets in one.<\/p>\n<h3>Storage<\/h3>\n<p>\nA logical continuation of the iteration process is storing information about clients for the service in ipset.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/126069799d95594be8611237e935189d.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNow we have the same SSH, and we don\u2019t write 100 IPs immediately, but specify the name of the ipset to interact with, and the next rule <code>DROP<\/code>. It can be reworked into a single rule 'Who isn\u2019t here should DROP,' but this way it is more visually clear.<\/p>\n<p>Now we have rules and sets. The main task is to create the set before writing the rule because otherwise iptables will not record the rule.<\/p>\n<h3>Overall Scheme<\/h3>\n<p>\nIn schematic form, everything I've described looks like this.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/4046e921cb5f466f8af5a6af1fcd151c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe commit to Puppet, everything is sent to the host, services are here, ipset is there, and whoever is not specified there is not allowed.<\/p>\n<h3>Allow &amp; deny<\/h3>\n<p>\nTo quickly save the world or quickly disconnect someone, at the beginning of all chains we created two ipsets: <code>rules_allow<\/code> and <code>rules_deny<\/code>. How does this work?<\/p>\n<p>For example, someone creates a load on our Web using bots. Previously, it was necessary to find their IP through the logs, report it to the network engineers so they could locate the traffic source and ban it. Now it works differently.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/6e7f906919536cab2c283ba6ceb0472d.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWe send it to Consul, wait 2.5 seconds, and it's done. Since Consul quickly distributes through P2P, it works everywhere, in any part of the world.<\/p>\n<p>Once, I completely stopped WOT due to an error with the firewall. <code>rules_allow<\/code> \u2014 this is our insurance against such cases. If we mistakenly misconfigure the firewall and something gets blocked, we can always send a conditional <code>0.0\/0<\/code>, to restore everything quickly. Later, we will fix everything manually.<\/p>\n<h3>Other sets<\/h3>\n<p>\nYou can add any other sets in the space <code>$IPSETS$<\/code>.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/4e1e337b35da81cd7324b2adc106b085.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWhy? Sometimes someone needs ipset, for example, to emulate the disconnection of a certain part of the cluster. Everyone can bring any sets, name them, and they will be pulled from Consul. At the same time, sets can either participate in iptables rules or act as a NOOP command. <code>NOOP<\/code>: consistency will be maintained by the daemon.<\/p>\n<h3>Users<\/h3>\n<p>\nIt used to be this way: a user would connect to the network and receive parameters via a domain. Before the advent of next-generation firewalls, Cisco could not understand where the user was and where the IP was. Therefore, access was granted only through the hostname of the machine.<\/p>\n<p>What did we do? We intervened at the moment of address acquisition. Usually, this is dot1x, Wi-Fi, or VPN\u2014all through RADIUS. For each user, we create a group named after the user and place the IP in it with a TTL equal to their dhcp.lease\u2014once it expires, the rule disappears.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/04550475c6af49d094c18b1d5b89123a.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNow we can grant access to services just like in other groups, by username. We eliminated the hassle with hostnames when they change and relieved the network engineers from the burden, as they no longer need Cisco. Now engineers can configure access on their servers themselves.<\/p>\n<h3>Isolation<\/h3>\n<p>\nAt the same time, we started examining isolation. Service managers conducted an inventory, and we analyzed all our networks. We will categorize them into similar groups, and on the required servers, we added groups, for example, in deny. Now the same staging isolation falls into rules_deny in production, but not directly into production.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/60fe7407013aa64b853791f8def627cc.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThe scheme works quickly and simply: we remove all ACLs from servers, lighten the hardware load, and reduce the number of isolated VLANs.<\/p>\n<h3>Integrity control<\/h3>\n<p>\nPreviously, we had a special trigger that alerted us when someone manually changed a firewall rule. I wrote a large linter to check firewall rules, which was complicated. Now, integrity is monitored by BEFW. It diligently ensures that the rules it creates are not altered. If someone changes the firewall rules, it will revert everything back. \"I quickly set up a proxy to work from home\" \u2014 options like this are no longer available.<\/p>\n<p>BEFW monitors ipset from services and the list in befw.conf; service rules are in the BEFW chain. However, it does not monitor other chains, rules, or ipsets.<\/p>\n<h3>Fault Protection<\/h3>\n<p>\nBEFW always saves the last successful state directly in the binary structure state.bin. If something goes wrong, it always reverts to this state.bin.<\/p>\n<p><img decoding=\"async\" alt=\"Consul + iptables = :3\" src=\"\/wp-content\/uploads\/2020\/02\/724f3537c06a7135fa6397f9ddd5630f.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThis acts as insurance against unstable Consul operation when it fails to send data or someone mistakenly uses rules that cannot be applied. To ensure we are not left without a firewall, BEFW will revert to the last state if an error occurs at any point.<\/p>\n<p>In critical situations, this guarantees that we will remain with a functioning firewall. We open all gray networks in the hope that an admin will come and fix them. Someday, I will incorporate this into the configs, but right now we only have three gray networks: 10\/8, 172\/12, and 192.168\/16. Within our Consul, this is an important feature that helps us progress further.<\/p>\n<p><em>Demo: during the presentation, Ivan demonstrates the demo mode of BEFW. The demonstration is easier to view on <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/4zP67uYnsR4?t=1663\">video<\/a><\/noindex>. The source code for the demo is available <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wgnet\/befw\/tree\/master\/demo\">on GitHub<\/a><\/noindex>.<\/em><\/p>\n<h2>Pitfalls<\/h2>\n<p>\nI will discuss the bugs we encountered.<\/p>\n<p><strong>ipset add set 0.0.0.0\/0. <\/strong>What happens if you add 0.0.0.0\/0 to ipset? Do all IPs get added? Is internet access opened? <\/p>\n<p>No, we will encounter a bug that cost us two hours of downtime. Notably, this bug has not worked since 2016, is listed in RedHat Bugzilla under number #1297092, and we found it accidentally \u2014 from a developer's report.<\/p>\n<p>Now, there is a strict rule in BEFW that <code>0.0.0.0\/0<\/code> turns into two addresses: <code>0.0.0.0\/1<\/code> and <code>128.0.0.0\/1<\/code>.<\/p>\n<p><strong>ipset restore set &lt; file. <\/strong>What does ipset do when you tell it to <code>restore<\/code>? \u0412\u044b \u0434\u0443\u043c\u0430\u0435\u0442\u0435, \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u0430\u043a\u0436\u0435, \u043a\u0430\u043a iptables? \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435?<\/p>\n<p>Nothing of the sort \u2014 it performs a merge, and the old addresses remain; you do not close access.<\/p>\n<p>We discovered the bug while testing isolation. Now, there is quite a complex system \u2014 instead of <code>restore<\/code> a temp is conducted <code>create temp<\/code>, then <code>restore flush temp<\/code> and <code>restore temp<\/code>. In the end, swap: for atomicity, because if conducted first <code>flush<\/code> And at that moment, if a package comes in, it will be discarded and something will go wrong. That's why there's a bit of black magic involved.<\/p>\n<p><strong>consul kv get -datacenter=other. <\/strong>As I mentioned earlier, we think we are requesting some data, but we will either get data or an error. We can do this through Consul locally, but even then both will freeze.<\/p>\n<p>The local Consul client is a wrapper around the HTTP API. However, it just hangs and does not respond to Ctrl+C, Ctrl+Z, or anything else, only to <code>kill -9<\/code> the adjacent console. We encountered this when building a large cluster. But we still have no solutions; we are preparing to fix this error in Consul.<\/p>\n<p><strong>Consul leader is unresponsive. <\/strong>The master in the data center is unresponsive; we think, 'Maybe the election algorithm will kick in now?' <\/p>\n<p>No, it won't, and monitoring won't show anything: Consul will say that the commitment index exists, the leader is found, everything is fine.<\/p>\n<p>How do we deal with this? <code>service consul restart<\/code> in cron every hour. If you have 50 servers, it's not a big deal. When you have 16,000, you'll understand how it works.<\/p>\n<h2>Conclusion<\/h2>\n<p>\nAs a result, we gained the following advantages:<\/p>\n<ul>\n<li>100% coverage of all Linux machines.<\/li>\n<li>Speed.<\/li>\n<li>Automation.<\/li>\n<li>Freed hardware and network engineers from servitude.<\/li>\n<li>Integration capabilities have become almost limitless: with Kubernetes, Ansible, or Python.<\/li>\n<\/ul>\n<p>\n<strong>Cons<\/strong>: Consul, which we now have to live with, and the cost of errors is very high. For example, once at 6 PM (prime time in Russia), I was adjusting the network lists. We were just building isolation on BEFW then. I made a mistake somewhere, I think, I specified the wrong mask, and everything crashed in two seconds. The monitoring lights up, the on-call support rushes in: 'Everything is down!' The department head turned gray when explaining to the business why it happened.<\/p>\n<p>The cost of errors is so high that we developed our own complex prevention procedure. If you're going to implement this in a large production environment, don't give the master token over Consul to everyone. It will end badly.<\/p>\n<p><strong>Cost. <\/strong>I wrote code for 400 hours alone. My team of 4 spends 10 hours a month supporting everyone. Compared to the cost of any next-gen firewall, this is free.<\/p>\n<p><strong>Plans. <\/strong>The long-term plan is to find an alternative transport to replace or supplement Consul. It might be Kafka or something similar. But in the coming years, we'll be living with Consul.<\/p>\n<p>Upcoming plans include integration with Fail2ban, monitoring, nftables, and possibly other distributions, metrics, enhanced monitoring, and optimization. Support for Kubernetes is also on the horizon, as we currently have several clusters and a desire for this capability.<\/p>\n<p>Additional plans include:<\/p>\n<ul>\n<li>anomaly detection in traffic;<\/li>\n<li>network map management;<\/li>\n<li>Kubernetes support;<\/li>\n<li>package builds for all systems;<\/li>\n<li>Web-UI.<\/li>\n<\/ul>\n<p>\nWe are continuously working on expanding configurations, increasing metrics, and optimizing.<\/p>\n<p><i>Join the project. It\u2019s become amazing, but unfortunately, it\u2019s still a one-person project. Come to <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wgnet\/befw\">GitHub <\/a><\/noindex>and try to contribute: commit, test something, make suggestions, or provide your feedback.<\/i><\/p>\n<blockquote><p>In the meantime, we are preparing for <noindex><a rel=\"nofollow\" href=\"https:\/\/www.highload.ru\/spb\/2020\">Saint HighLoad++<\/a><\/noindex>, which will take place on April 6 and 7 in Saint Petersburg, and we invite developers of high-load systems <noindex><a rel=\"nofollow\" href=\"https:\/\/conf.ontico.ru\/lectures\/propose?conference=hl2020-spb\">to submit a proposal to speak<\/a><\/noindex>. Experienced speakers already know what to do, while beginners are advised to at least <noindex><a rel=\"nofollow\" href=\"https:\/\/www.highload.ru\/spb\/2020\/speakers\">try<\/a><\/noindex>. Being a speaker at the conference has several advantages. You can read about them, for instance, at the end of <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/oleg-bunin\/blog\/486142\/\">of this article<\/a><\/noindex>.<\/p><\/blockquote>\n<p>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/oleg-bunin\/blog\/486842\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 2010 \u0433\u043e\u0434\u0443 \u0443 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Wargaming \u0431\u044b\u043b\u043e 50 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0441\u0435\u0442\u0435\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c: \u0431\u044d\u043a\u0435\u043d\u0434, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0438 \u0444\u0430\u0439\u0440\u0432\u043e\u043b. \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0440\u043e\u0441\u043b\u043e, \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u043b\u0430\u0441\u044c: \u0441\u0442\u0435\u0439\u0434\u0436\u0438\u043d\u0433\u0438, \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 VLAN \u0441 ACL, \u043f\u043e\u0442\u043e\u043c VPN \u0441 VRF, VLAN c ACL \u043d\u0430 L2, VRF \u0441 ACL \u043d\u0430 L3. \u0417\u0430\u043a\u0440\u0443\u0436\u0438\u043b\u0430\u0441\u044c \u0433\u043e\u043b\u043e\u0432\u0430? \u0414\u0430\u043b\u044c\u0448\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0441\u0435\u043b\u0435\u0435. \u041a\u043e\u0433\u0434\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0441\u0442\u0430\u043b\u043e 16 000 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u0435\u0437 \u0441\u043b\u0435\u0437 \u0441 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":41052,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-41051","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 2010 \u0433\u043e\u0434\u0443 \u0443 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Wargaming \u0431\u044b\u043b\u043e 50 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0441\u0435\u0442\u0435\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c: \u0431\u044d\u043a\u0435\u043d\u0434, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0438 \u0444\u0430\u0439\u0440\u0432\u043e\u043b.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/consul-iptables-3\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47Consul + iptables = :3 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 2010 \u0433\u043e\u0434\u0443 \u0443 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Wargaming \u0431\u044b\u043b\u043e 50 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0441\u0435\u0442\u0435\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c: \u0431\u044d\u043a\u0435\u043d\u0434, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0438 \u0444\u0430\u0439\u0440\u0432\u043e\u043b.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/consul-iptables-3\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-02-05T18:28:58+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-05T18:28:58+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Consul + iptables = :3 | ProHoster","description":"In 2010, Wargaming had 50 servers and a simple network model: backend, frontend, and firewall.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/consul-iptables-3","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47Consul + iptables = :3 | ProHoster","og:description":"\u0412 2010 \u0433\u043e\u0434\u0443 \u0443 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Wargaming \u0431\u044b\u043b\u043e 50 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0441\u0435\u0442\u0435\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c: \u0431\u044d\u043a\u0435\u043d\u0434, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0438 \u0444\u0430\u0439\u0440\u0432\u043e\u043b.","og:url":"https:\/\/prohoster.info\/en\/blog\/consul-iptables-3","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-02-05T18:28:58+00:00","article:modified_time":"2020-02-05T18:28:58+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"41051","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 00:24:42","updated":"2022-10-01 10:00:06","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/41051","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=41051"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/41051\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/41052"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=41051"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=41051"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=41051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}