Thursday, September 29, 2016

How to Install Git over HTTP on CentOS x








There is already a bunch of posts about setting up Git over HTTP(S), but this one is specificaly targeted at setting it up under CentOS as cleanly as possible. There was bunch of errors that I saw along the way, so I will try to explain the process step by step.

First, you have to install Apache and Git.:
# yum -y install httpd git
# /etc/init.d/httpd start

Now, let’s create directories for git and create our first repo:
# mkdir /var/www/html/gitrepos
# cd /var/www/html/gitrepos
# mkdir repo01 && cd repo01
# git --bare init
# git update-server-info
# cd /var/www/html
# chown -R apache: gitrepos

We are using ‘git –bare’, so that online repository doesn’t have files but only git metadata. That will enable users to push directly to online repository, otherwise they wouldn’t be able to push thier changes. This was the first error I did, I created repo with ‘git init’ and was not able to push later. After the repo is set up and chowned, lets set up apache.

This is my configuration for vhost:
#
# vhost for git repositories (http)
#
<VirtualHost *:80>
    ServerName     git
    DocumentRoot    /var/www/html/gitrepos

    <Location />
        DAV on

        # general auth settings
        AuthName "Git login:"
        AuthType Basic

        # file authentication
        AuthUserFile  /var/www/html/.htpasswd
        AuthGroupFile /var/www/html/.htgroup

        <LimitExcept PROPFIND>
            Require valid-user
        </LimitExcept>
    </Location>

    <Location /repo01>
        <LimitExcept PROPFIND>
            Require group adminlinux
        </LimitExcept>
    </Location>

    LogLevel warn
    ErrorLog  /var/log/httpd/git_error.log
    CustomLog /var/log/httpd/git_access.log combined
</VirtualHost>
#
We can fill up htpasswd file with – htpasswd command
# htpasswd -c /var/www/html/.htpasswd user1
# htpasswd -c /var/www/html/.htpasswd user2
# htpasswd -c /var/www/html/.htpasswd user3

And htgroup with:
# echo "adminlinux: user1 user2" >> /var/www/html/.htgroup

Now, on the client side, do a:

After the first change/commit you do, be careful when you push those changes for the first time.
This is the command I used for the first push:
% git push --set-upstream origin master

And that’s it!...

Friday, September 23, 2016

How To Install Puppet 4 in a Master-Agent Setup on CentOS 7


Introduction

Puppet, from Puppet Labs, is a configuration management tool that helps system administrators automate the provisioning, configuration, and management of a server infrastructure. Planning ahead and using config management tools like Puppet can cut down on time spent repeating basic tasks, and help ensure that your configurations are consistent and accurate across your infrastructure. Once you get the hang of managing your servers with Puppet and other automation tools, you will have more free time that can be used to improve other aspects of your setup.

Puppet comes in two varieties, Puppet Enterprise and open source Puppet. It runs on most Linux distributions, various UNIX platforms, and Windows.

In this tutorial, we will cover how to install open source Puppet 4 in an agent/master setup on CentOS 7. In this setup, the Puppet master server—which runs the Puppet Server software—can be used to control all your other servers, or Puppet agent nodes. Note that we'll be using the Puppet Server package, instead of Passenger or any other runtime environment.

Prerequisites

To follow this tutorial, you must have root or superuser access to all of the servers that you want to use Puppet with. You will also be required to create a new CentOS 7 server to act as the Puppet master server. If you do not have an existing server infrastructure, feel free to recreate the example infrastructure (described below) by following the prerequisite DNS setup tutorial.

Before we get started with installing Puppet, ensure that you have the following prerequisites:

Private Network DNS: Forward and reverse DNS must be configured, and each server must have a unique hostname. Here is a tutorial to configure your own private network DNS server. If you do not have DNS configured, you must use your hosts file for name resolution. We will assume that you will use your private network for communication within your infrastructure.

Firewall Open Ports: The Puppet master must be reachable on port 8140. If your firewall is too restrictive, check out this FirewallD Tutorial for instructions on how to allow incoming requests on port 8140.

Example Infrastructure

We will use the following infrastructure to demonstrate how to set up Puppet:
Hostname
Role
Private FQDN
host1
Generic CentOS 7 server
host1.nyc3.example.com
host2
Generic CentOS 7 server
host2.nyc3.example.com
ns1
Primary nameserver
ns1.nyc3.example.com
ns2
Secondary nameserver
ns2.nyc3.example.com

The puppet agent will be installed on all of these hosts. These hosts will be referenced by their private network interfaces, which are mapped to the ".nyc3.example.com" subdomain in DNS. This is the same infrastructure that is described in the prerequisite tutorial: How To Configure BIND as a Private Network DNS Server on CentOS 7.
Once you have all of the prerequisites, let's move on to creating the Puppet master server!

Create Puppet Master Server

Create a new CentOS 7 x64 server, using "puppet" as its hostname. The hardware requirements depend on how many agent nodes you want to manage; two CPU cores and 1 GB of memory is the minimum requirement to manage a handful of nodes, but you'll need more resources if your server infrastructure is larger. Puppet Server is configured to use 2 GB of RAM by default.

Hostname
Role
Private FQDN
puppet
Puppet master
puppet.nyc3.example.com

If you just set up your DNS and are unsure how to include new hosts, refer to the Maintaining DNS Records section of the DNS tutorial. Essentially, you need to add an "A" and "PTR" record, and allow the new host to perform recursive queries. Also, ensure that you configure your search domain so your servers can use short hostnames to look up each other.

Note: This tutorial assumes that your Puppet master's hostname is "puppet". If you use a different name, you will need to make a few deviations from this tutorial. Specifically, you must specify your Puppet master's hostname in your Puppet agent nodes' configuration files, and you must regenerate your Puppet master's SSL certificate before signing any agent certificates. Otherwise, you will receive this error: Error: Could not request certificate: The certificate retrieved from the master does not match the agent's private key..
Configuring this setting is not covered in this tutorial.

Install NTP

Because it acts as a certificate authority for agent nodes, the Puppet master server must maintain accurate system time to avoid potential problems when it issues agent certificates--certificates can appear to be expired if there are time discrepancies. We will use Network Time Protocol (NTP) for this purpose.

First, take a look at the available timezones with this command:
timedatectl list-timezones

This will give you a list of the timezones available for your server. When you find the region/timezone setting that is correct for your server, set it with this command (substitute your preferred region and timezone):
sudo timedatectl set-timezone America/New_York

Install NTP via yum with this command:
sudo yum -y install ntp

Do a one-time time synchronization using the ntpdate command:
sudo ntpdate pool.ntp.org

It is common practice to update the NTP configuration to use "pools zones" that are geographically closer to your NTP server. In a web browser, go to the NTP Pool Project and look up a pool zone that is geographically close the datacenter that you are using. We will use the United States pool (http://www.pool.ntp.org/zone/us) in our example, because our servers are located in a New York datacenter.
Open ntp.conf for editing:

sudo vi /etc/ntp.conf

Add the time servers from the NTP Pool Project page to the top of the file (replace these with the servers of your choice):

/etc/ntp.conf excerpt
server 0.us.pool.ntp.org
server 1.us.pool.ntp.org
server 2.us.pool.ntp.org
server 3.us.pool.ntp.org
Save and exit.

Start NTP to add the new time servers:
sudo systemctl restart ntpd

Lastly, enable the NTP daemon:
sudo systemctl enable ntpd

Now that our server is keeping accurate time, let's install the Puppet Server software.

Install Puppet Server

Puppet Server is the software that runs on the Puppet master server. It is the component that will push configurations to your other servers, which will be running the Puppet agent software.

Enable the official Puppet Labs collection repository with this command:

sudo rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm

Install the puppetserver package:

sudo yum -y install puppetserver

Puppet Server is now installed on your master server, but it is not running yet.

Configure Memory Allocation (optional)

By default, Puppet Server is configured to use 2 GB of RAM. You should customize this setting based on how much free memory your master server has, and how many agent nodes it will manage.

First, open /etc/sysconfig/puppetserver in your favorite text editor. We'll use vi:

sudo vi /etc/sysconfig/puppetserver

Then find the JAVA_ARGS line, and use the -Xms and -Xmx parameters to set the memory allocation. For example, if you want to use 3 GB of memory, the line should look like this:

JAVA_ARGS="-Xms3g -Xmx3g"
Save and exit when you're done.

Start Puppet Server

Now we're ready to start Puppet Server with this command:

sudo systemctl start puppetserver

Next, enable Puppet Server so that it starts when your master server boots:

sudo systemctl enable puppetserver

Puppet Server is running, but it isn't managing any agent nodes yet. Let's learn how to install and add Puppet agents!


Install Puppet Agent

The Puppet agent software must be installed on any server that the Puppet master will manage. In most cases, this will include every server in your infrastructure. As mentioned in the introduction, the Puppet agent can run on all major Linux distributions, some UNIX platforms, and Windows. Because the installation varies on each OS slightly, we will only cover the installation on CentOS 7 servers. Instructions on installing the Puppet agent on Ubuntu 14.04 servers can be found here.

Perform these steps on all of your agent servers.
Enable the official Puppet Labs collection repository with this command:
sudo rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm

Install the puppet-agent package:

sudo yum -y install puppet-agent

Now that the Puppet agent is installed, start it with this command:

sudo /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true

The first time you run the Puppet agent, it generates an SSL certificate and sends a signing request to the Puppet master. After the Puppet master signs the agent's certificate, it will be able to communicate with and control the agent node.

Remember to repeat this section for all of your Puppet agent nodes.

Note: If this is your first Puppet agent, it is recommended that you attempt to sign the certificate on the Puppet master, which is covered in the next step, before adding your other agents. Once you have verified that everything works properly, then you can go back and add the remaining agent nodes with confidence.

Sign Certificates on Puppet Master

The first time Puppet runs on an agent node, it will send a certificate signing request to the Puppet master. Before Puppet Server will be able to communicate with and control the agent node, it must sign that particular agent node's certificate. We will describe how to sign and check for signing requests.

List Current Certificate Requests

On the Puppet master, run the following command to list all unsigned certificate requests:
sudo /opt/puppetlabs/bin/puppet cert list

If you just set up your first agent node, you will see one request. It will look something like the following, with the agent node's hostname:

Output:
  "host1.nyc3.example.com" (SHA256) 15:90:C2:FB:ED:69:A4:F7:B1:87:0B:BF:F7:DD:B5:1C:33:F7:76:67:F3:F6:23:AE:07:4B:F6:E3:CC:04:11:4C

Note that there is no + in front of it. This indicates that it has not been signed yet.

Sign A Request

To sign a certificate request, use the puppet cert sign command, with the hostname of the certificate you want to sign. For example, to sign host1.nyc3.example.com's certificate, you would use the following command:

sudo /opt/puppetlabs/bin/puppet cert sign host1.nyc3.example.com

You will see the following output, which indicates that the certificate request has been signed:

Output:
Notice: Signed certificate request for host1.nyc3.example.com
Notice: Removing file Puppet::SSL::CertificateRequest host1.nyc3.example.com at '/etc/puppetlabs/puppet/ssl/ca/requests/host1.nyc3.example.com.pem'

The Puppet master can now communicate and control the node that the signed certificate belongs to.

If you want to sign all of the current requests, use the --all option, like so:
sudo /opt/puppetlabs/bin/puppet cert sign --all

Revoke Certificates

You may want to remove a host from Puppet, or rebuild a host then add it back to Puppet. In this case, you will want to revoke the host's certificate from the Puppet master. To do this, you can use the clean action:

sudo /opt/puppetlabs/bin/puppet cert clean hostname

The specified host's associated certificates will be removed from Puppet.

View All Signed Requests
If you want to view all of the requests, signed and unsigned, run the following command:
sudo /opt/puppetlabs/bin/puppet cert list --all

You will see a list of all of the requests. Signed requests are preceded by a + and unsigned requests do not have the +.

Output:
+ "puppet"    (SHA256) 5A:71:E6:06:D8:0F:44:4D:70:F0:BE:51:72:15:97:68:D9:67:16:41:B0:38:9A:F2:B2:6C:BB:33:7E:0F:D4:53 (alt names: "DNS:puppet", "DNS:puppet.nyc3.example.com")
+ "host1.nyc3.example.com" (SHA256) F5:DC:68:24:63:E6:F1:9E:C5:FE:F5:1A:90:93:DF:19:F2:28:8B:D7:BD:D2:6A:83:07:BA:FE:24:11:24:54:6A
+ "host2.nyc3.example.com" (SHA256) CB:CB:CA:48:E0:DF:06:6A:7D:75:E6:CB:22:BE:35:5A:9A:B3:93:63:BF:F0:DB:F2:D8:E5:A6:27:10:71:78:DA
+ "ns2.nyc3.example.com" (SHA256) 58:47:79:8A:56:DD:06:39:52:1F:E3:A0:F0:16:ED:8D:40:17:40:76:C2:F0:4F:F3:0D:F9:B3:64:48:2E:F1:CF
Congrats! Your infrastructure is now ready to be managed by Puppet!


Getting Started with Puppet

Now that your infrastructure is set up to be managed with Puppet, we will show you how to use Puppet to do a few basic tasks.
How Facts Are Gathered

Puppet gathers facts about each of its nodes with a tool called facter. Facter, by default, gathers information that is useful for system configuration (e.g. OS names, hostnames, IP addresses, SSH keys, and more). It is possible to add custom facts that aren't part of the default fact set.

The facts gathered can be useful in many situations. For example, you can create an web server configuration template and automatically fill in the appropriate IP addresses for a particular virtual host. Or you can determine that your server's distribution is "CentOS", so you should run the apache2 service instead of httpd. These are basic examples, but they should give you an idea of how facts can be used.

To see a list of facts that are automatically being gathered on your agent node, run the following command:
/opt/puppetlabs/bin/facter

Main Manifest File

Puppet uses a domain-specific language to describe system configurations, and these descriptions are saved to files called "manifests", which have a .pp file extension. The default main manifest file is located on your Puppet master server at /etc/puppetlabs/code/environments/production/manifests/site.pp. Let's create a placeholder file for now:

sudo touch /etc/puppetlabs/code/environments/production/manifests/site.pp

Note that the main manifest is empty right now, so Puppet won't perform any configuration on the agent nodes.

How The Main Manifest Is Executed

The Puppet agent periodically checks in with the Puppet Server (typically every 30 minutes). When it checks in, it will send facts about itself to the master, and pull a current catalog--a compiled list of resources and their desired states that are relevant to the agent, determined by the main manifest. The agent node will then attempt to make the appropriate changes to achieve its desired state. This cycle will continue as long as the Puppet master is running and communicating with the agent nodes.

Immediate Execution on a Particular Agent Node

It is also possible to initiate the check for a particular agent node manually, by running the following command (on the agent node in question):

/opt/puppetlabs/bin/puppet agent --test

Running this will apply the main manifest to the agent running the test. You might see output like the following:

Output:
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
...
Info: Loading facts
Info: Caching catalog for host1
Info: Applying configuration version '1457389302'
Notice: /Stage[main]/Main/File[/tmp/example-ip]/ensure: defined content as '{md5}dd769ec60ea7d4f7146036670c6ac99f'
Notice: Applied catalog in 0.04 seconds

This command is useful for seeing how the main manifest will affect a single server immediately.


One-off Manifests

The puppet apply command allows you to execute manifests that are not related to the main manifest, on demand. It only applies the manifest to the node that you run the apply from. Here is an example:

sudo /opt/puppetlabs/bin/puppet apply /path/to/your/manifest/init.pp

Running manifests in this fashion is useful if you want to test a new manifest on an agent node, or if you just want to run a manifest once (e.g. to initialize an agent node to a desired state).

An Example Manifest

As you may recall, the main manifest file on the Puppet master is located at /etc/puppetlabs/code/environments/production/manifests/site.pp.

On the Puppet master server, edit it now:

sudo vi /etc/puppetlabs/code/environments/production/manifests/site.pp

Now add the following lines to describe a file resource:

file {'/tmp/example-ip':                                            # resource type file and filename

  ensure  => present,                                               # make sure it exists

  mode    => '0644',                                                # file permissions

  content => "Here is my Public IP Address: ${ipaddress_eth0}.\n",  # note the ipaddress_eth0 fact

}

Now save and exit. The inline comments should explain the resource that we are defining. In plain English, this will ensure that all agent nodes will have a file at /tmp/example-ip with -rw-r--r-- permissions, with content that includes the node's public IP address.

You can either wait until the agent checks in with the master automatically, or you can run the /opt/puppetlabs/bin/puppet agent --test command (from one of your agent nodes). Then run the following command to print the file:

cat /tmp/example-ip

You should see output that looks like the following (with that node's IP address):

Output:
Here is my Public IP Address: 128.131.192.11.


Using a Module

Now let's use a module. Modules are useful for grouping tasks together. There are many modules available in the Puppet community, and you can even write your own.

On the Puppet master, install the puppetlabs-apache module from forgeapi:
sudo /opt/puppetlabs/bin/puppet module install puppetlabs-apache

Warning: Do not use this module on an existing Apache setup. It will purge any Apache configurations that are not managed by Puppet.

Now edit site.pp:
sudo vi /etc/puppetlabs/code/environments/production/manifests/site.pp

Now add the following lines to install Apache on host2:

site.pp example
node 'host2' {
  class { 'apache': }             # use apache module
  apache::vhost { 'example.com':  # define vhost resource
    port    => '80',
    docroot => '/var/www/html'
  }
}
# node default {}       # uncomment this line if it doesn't already exist in your manifest

Save and exit. Now the next time Puppet updates host2, it will install the Apache package, and configure a virtual host called "example.com", listening on port 80, and with a document root /var/www/html.

On host2, run the following command:
sudo /opt/puppetlabs/bin/puppet agent --test

You should see a bunch of output indicating that Apache is being installed. Once it is complete, open host2's public IP address in a web browser. You should see a page that is being served by Apache.

Congrats! You have used your first Puppet module!

Conclusion
Now that you have a basic agent/master Puppet installation, you are now ready to learn more about how to use Puppet to manage your server infrastructure. Check out the following tutorial: Getting Started With Puppet Code: Manifests and Modules.



Friday, September 9, 2016

How to Set Up a Firewall Using FirewallD on CentOS 7

Introduction
Firewalld is a complete firewall solution available by default on CentOS 7 servers. In this guide, we will cover how to set up a firewall for your server and show you the basics of managing the firewall with thefirewall-cmd administrative tool (if you'd rather use iptables with CentOS, follow this guide).
Basic Concepts in Firewalld
Before we begin talking about how to actually use the firewall-cmd utility to manage your firewall configuration, we should get familiar with a few basic concepts that the tool introduces.
Zones
The firewalld daemon manages groups of rules using entities called "zones". Zones are basically sets of rules dictating what traffic should be allowed depending on the level of trust you have in the networks your computer is connected to. Network interfaces are assigned a zone to dictate the behavior that the firewall should allow.
For computers that might move between networks frequently (like laptops), this kind of flexibility provides a good method of changing your rules depending on your environment. You may have strict rules in place prohibiting most traffic when operating on a public WiFi network, while allowing more relaxed restrictions when connected to your home network. For a server, these zones are not as immediately important because the network environment rarely, if ever, changes.
Regardless of how dymaic your network environment may be, it is still useful to be familiar with the general idea behind each of the pre-defined zones for firewalld. In order from least trusted to most trusted, the pre-defined zones within firewalld are:
·         drop: The lowest level of trust. All incoming connections are dropped without reply and only outgoing connections are possible.
·         block: Similar to the above, but instead of simply dropping connections, incoming requests are rejected with an icmp-host-prohibited or icmp6-adm-prohibited message.
·         public: Represents public, untrusted networks. You don't trust other computers but may allow selected incoming connections on a case-by-case basis.
·         external: External networks in the event that you are using the firewall as your gateway. It is configured for NAT masquerading so that your internal network remains private but reachable.
·         internal: The other side of the external zone, used for the internal portion of a gateway. The computers are fairly trustworthy and some additional services are available.
·         dmz: Used for computers located in a DMZ (isolated computers that will not have access to the rest of your network). Only certain incoming connections are allowed.
·         work: Used for work machines. Trust most of the computers in the network. A few more services might be allowed.
·         home: A home environment. It generally implies that you trust most of the other computers and that a few more services will be accepted.
·         trusted: Trust all of the machines in the network. The most open of the available options and should be used sparingly.
To use the firewall, we can create rules and alter the properties of our zones and then assign our network interfaces to whichever zones are most appropriate.
Rule Permanence
In firewalld, rules can be designated as either permanent or immediate. If a rule is added or modified, by default, the behavior of the currently running firewall is modified. At the next boot, the old rules will be reverted.
Most firewall-cmd operations can take the --permanent flag to indicate that the non-ephemeral firewall should be targeted. This will affect the rule set that is reloaded upon boot. This separation means that you can test rules in your active firewall instance and then reload if there are problems. You can also use the --permanent flag to build out an entire set of rules over time that will all be applied at once when the reload command is issued.
Turning on the Firewall
Before we can begin to create our firewall rules, we need to actually turn the daemon on. The systemdunit file is called firewalld.service. We can start the daemon for this session by typing:
·         sudo systemctl start firewalld.service
·         sudo systemctl enable firewalld

We can verify that the service is running and reachable by typing:
·         firewall-cmd --state
output
running

This indicates that our firewall is up and running with the default configuration.
At this point, we will not enable the service. Enabling the service would cause the firewall to start up at boot. We should wait until we have created our firewall rules and had an opportunity to test them before configuring this behavior. This can help us avoid being locked out of the machine if something goes wrong.
Getting Familiar with the Current Firewall Rules
Before we begin to make modifications, we should familiarize ourselves with the default environment and rules provided by the daemon.
Exploring the Defaults
We can see which zone is currently selected as the default by typing:
·         firewall-cmd --get-default-zone
output
public

Since we haven't given firewalld any commands to deviate from the default zone, and none of our interfaces are configured to bind to another zone, that zone will also be the only "active" zone (the zone that is controlling the traffic for our interfaces). We can verify that by typing:
·         firewall-cmd --get-active-zones
output
public
  interfaces: eth0 eth1

Here, we can see that we have two network interfaces being controlled by the firewall (eth0 and eth1). They are both currently being managed according to the rules defined for the public zone.
How do we know what rules are associated with the public zone though? We can print out the default zone's configuration by typing:
·         firewall-cmd --list-all
output
public (default, active)
  interfaces: eth0 eth1
  sources:
  services: dhcpv6-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

We can tell from the output that this zone is both the default and active and that the eth0 and eth1interfaces are associated with this zone (we already knew all of this from our previous inquiries). However, we can also see that this zone allows for the normal operations associated with a DHCP client (for IP address assignment) and SSH (for remote administration).
Exploring Alternative Zones
Now we have a good idea about the configuration for the default and active zone. We can find out information about other zones as well.
To get a list of the available zones, type:
·         firewall-cmd --get-zones
output
block dmz drop external home internal public trusted work

We can see the specific configuration associated with a zone by including the --zone= parameter in our --list-all command:
·         firewall-cmd --zone=home --list-all
output
home
  interfaces:
  sources:
  services: dhcpv6-client ipp-client mdns samba-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

You can output all of the zone definitions by using the --list-all-zones option. You will probably want to pipe the output into a pager for easier viewing:
·         firewall-cmd --list-all-zones | less

Selecting Zones for your Interfaces
Unless you have configured your network interfaces otherwise, each interface will be put in the default zone when the firewall is booted.
Changing the Zone of an Interface for the Current Session
You can transition an interface between zones during a session by using the --zone= parameter in combination with the --change-interface= parameter. As with all commands that modify the firewall, you will need to use sudo.
For instance, we can transition our eth0 interface to the "home" zone by typing this:
·         sudo firewall-cmd --zone=home --change-interface=eth0
output
success
Note
Whenever you are transitioning an interface to a new zone, be aware that you are probably modifying the services that will be operational. For instance, here we are moving to the "home" zone, which has SSH available. This means that our connection shouldn't drop. Some other zones do not have SSH enabled by default and if your connection is dropped while using one of these zones, you could find yourself unable to log back in.

We can verify that this was successful by asking for the active zones again:
·         firewall-cmd --get-active-zones
output
home
  interfaces: eth0
public
  interfaces: eth1

If the firewall is completely restarted, the interface will revert to the default zone:
·         sudo systemctl restart firewalld.service
·         firewall-cmd --get-active-zones
output
public
  interfaces: eth0 eth1
Changing the Zone of your Interface Permanently
Interfaces will always revert to the default zone if they do not have an alternative zone defined within their configuration. On CentOS, these configurations are defined within the /etc/sysconfig/network-scriptsdirectory with files of the format ifcfg-interface.
To define a zone for the interface, open up the file associated with the interface you'd like to modify. We'll demonstrate making the change we showed above permanent:
·         sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0

At the bottom of the file, set the ZONE= variable to the zone you wish to associate with the interface. In our case, this would be the "home" interface:
/etc/sysconfig/network-scripts/ifcfg-eth0
. . .

DNS1=2001:4860:4860::8844
DNS2=2001:4860:4860::8888
DNS3=8.8.8.8
ZONE=home
Save and close the file.
To implement your changes, you'll have to restart the network service, followed by the firewall service:
·         sudo systemctl restart network.service
·         sudo systemctl restart firewalld.service

After your firewall restarts, you can see that your eth0 interface is automatically placed in the "home" zone:
·         firewall-cmd --get-active-zones
output
home
  interfaces: eth0
public
  interfaces: eth1

Make sure to revert these changes if this is not the actual zone you'd like to use for this interface.
Adjusting the Default Zone
If all of your interfaces can best be handled by a single zone, it's probably easier to just select the best default zone and then use that for your configuration.
You can change the default zone with the --set-default-zone= parameter. This will immediately change any interface that had fallen back on the default to the new zone:
·         sudo firewall-cmd --set-default-zone=home
output
home
  interfaces: eth0 eth1
Setting Rules for your Applications
The basic way of defining firewall exceptions for the services you wish to make available is easy. We'll run through the basic idea here.
Adding a Service to your Zones
The easiest method is to add the services or ports you need to the zones you are using. Again, you can get a list of the available services with the --get-services option:
·         firewall-cmd --get-services
output
RH-Satellite-6 amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns ftp high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind samba samba-client smtp ssh telnet tftp tftp-client transmission-client vnc-server wbem-https

Note
You can get more details about each of these services by looking at their associated .xml file within the /usr/lib/firewalld/services directory. For instance, the SSH service is defined like this:
/usr/lib/firewalld/services/ssh.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>SSH</short>
  <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
  <port protocol="tcp" port="22"/>
</service>

You can enable a service for a zone using the --add-service= parameter. The operation will target the default zone or whatever zone is specified by the --zone= parameter. By default, this will only adjust the current firewall session. You can adjust the permanent firewall configuration by including the --permanentflag.
For instance, if we are running a web server serving conventional HTTP traffic, we can allow this traffic for interfaces in our "public" zone for this session by typing:
·         sudo firewall-cmd --zone=public --add-service=http

You can leave out the --zone= if you wish to modify the default zone. We can verify the operation was successful by using the --list-all or --list-services operations:
·         firewall-cmd --zone=public --list-services
output
dhcpv6-client http ssh

Once you have tested that everything is working as it should, you will probably want to modify the permanent firewall rules so that your service will still be available after a reboot. We can make our "public" zone change permanent by typing:
·         sudo firewall-cmd --zone=public --permanent --add-service=http

You can verify that this was successful by adding the --permanent flag to the --list-servicesoperation. You need to use sudo for any --permanent operations:
·         sudo firewall-cmd --zone=public --permanent --list-services
output
dhcpv6-client http ssh

Your "public" zone will now allow HTTP web traffic on port 80. If your web server is configured to use SSL/TLS, you'll also want to add the https service. We can add that to the current session and the permanent rule-set by typing:
·         sudo firewall-cmd --zone=public --add-service=https
·         sudo firewall-cmd --zone=public --permanent --add-service=https

·         And now reload the firewall to apply changes:
firewall-cmd --reload
 
·         Verify the service port has been opened:
firewall-cmd --zone=public --query-service=http

What If No Appropriate Service Is Available?
The firewall services that are included with the firewalld installation represent many of the most common requirements for applications that you may wish to allow access to. However, there will likely be scenarios where these services do not fit your requirements.
In this situation, you have two options.
Opening a Port for your Zones
The easiest way to add support for your specific application is to open up the ports that it uses in the appropriate zone(s). This is as easy as specifying the port or port range, and the associated protocol for the ports you need to open.
For instance, if our application runs on port 5000 and uses TCP, we could add this to the "public" zone for this session using the --add-port= parameter. Protocols can be either tcp or udp:
·         sudo firewall-cmd --zone=public --add-port=5000/tcp

We can verify that this was successful using the --list-ports operation:
·         firewall-cmd --list-ports
output
5000/tcp

It is also possible to specify a sequential range of ports by separating the beginning and ending port in the range with a dash. For instance, if our application uses UDP ports 4990 to 4999, we could open these up on "public" by typing:
·         sudo firewall-cmd --zone=public --add-port=4990-4999/udp

After testing, we would likely want to add these to the permanent firewall. You can do that by typing:
·         sudo firewall-cmd --zone=public --permanent --add-port=5000/tcp
·         sudo firewall-cmd --zone=public --permanent --add-port=4990-4999/udp
·         sudo firewall-cmd --zone=public --permanent --list-ports
output
success
success
4990-4999/udp 5000/tcp

To remove the port or service you added.

firewall-cmd --zone=public --remove-port=80/tcp
firewall-cmd --zone=public --remove-service=http


Defining a Service
Opening ports for your zones is easy, but it can be difficult to keep track of what each one is for. If you ever decommission a service on your server, you may have a hard time remembering which ports that have been opened are still required. To avoid this situation, it is possible to define a service.
Services are simply collections of ports with an associated name and description. Using services is easier to administer than ports, but requires a bit of upfront work. The easiest way to start is to copy an existing script (found in /usr/lib/firewalld/services) to the /etc/firewalld/services directory where the firewall looks for non-standard definitions.
For instance, we could copy the SSH service definition to use for our "example" service definition like this. The filename minus the .xml suffix will dictate the name of the service within the firewall services list:
·         sudo cp /usr/lib/firewalld/services/service.xml /etc/firewalld/services/example.xml

Now, you can adjust the definition found in the file you copied:
sudo nano /etc/firewalld/services/example.xml

To start, the file will contain the SSH definition that you copied:
/etc/firewalld/services/example.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>SSH</short>
  <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
  <port protocol="tcp" port="22"/>
</service>

The majority of this definition is actually metadata. You will want to change the short name for the service within the <short> tags. This is a human-readable name for your service. You should also add a description so that you have more information if you ever need to audit the service. The only configuration you need to make that actually affects the functionality of the service will likely be the port definition where you identify the port number and protocol you wish to open. This can be specified multiple times.
For our "example" service, imagine that we need to open up port 7777 for TCP and 8888 for UDP. We could modify the existing definition with something like this:
/etc/firewalld/services/example.xml

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Example Service</short>
  <description>This is just an example service.  It probably shouldn't be used on a real system.</description>
  <port protocol="tcp" port="7777"/>
  <port protocol="udp" port="8888"/>
</service>
Save and close the file.
Reload your firewall to get access to your new service:
·         sudo firewall-cmd --reload

You can see that it is now among the list of available services:
·         firewall-cmd --get-services
output
RH-Satellite-6 amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns example ftp high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind samba samba-client smtp ssh telnet tftp tftp-client transmission-client vnc-server wbem-https

You can now use this service in your zones as you normally would.
Creating Your Own Zones
While the predefined zones will probably be more than enough for most users, it can be helpful to define your own zones that are more descriptive of their function.
For instance, you might want to create a zone for your web server, called "publicweb". However, you might want to have another zone configured for the DNS service you provide on your private network. You might want a zone called "privateDNS" for that.
When adding a zone, you must add it to the permanent firewall configuration. You can then reload to bring the configuration into your running session. For instance, we could create the two zones we discussed above by typing:
·         sudo firewall-cmd --permanent --new-zone=publicweb
·         sudo firewall-cmd --permanent --new-zone=privateDNS

You can verify that these are present in your permanent configuration by typing:
·         sudo firewall-cmd --permanent --get-zones
output
block dmz drop external home internal privateDNS public publicweb trusted work

As stated before, these won't be available in the current instance of the firewall yet:
·         firewall-cmd --get-zones
output
block dmz drop external home internal public trusted work

Reload the firewall to bring these new zones into the active configuration:
·         sudo firewall-cmd --reload
·         firewall-cmd --get-zones
output
block dmz drop external home internal privateDNS public publicweb trusted work

Now, you can begin assigning the appropriate services and ports to your zones. It's usually a good idea to adjust the active instance and then transfer those changes to the permanent configuration after testing. For instance, for the "publicweb" zone, you might want to add the SSH, HTTP, and HTTPS services:
·         sudo firewall-cmd --zone=publicweb --add-service=ssh
·         sudo firewall-cmd --zone=publicweb --add-service=http
·         sudo firewall-cmd --zone=publicweb --add-service=https
·         firewall-cmd --zone=publicweb --list-all
output
publicweb
  interfaces:
  sources:
  services: http https ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

Likewise, we can add the DNS service to our "privateDNS" zone:
·         sudo firewall-cmd --zone=privateDNS --add-service=dns
·         firewall-cmd --zone=privateDNS --list-all
output
privateDNS
  interfaces:
  sources:
  services: dns
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

We could then change our interfaces over to these new zones to test them out:
·         sudo firewall-cmd --zone=publicweb --change-interface=eth0
·         sudo firewall-cmd --zone=privateDNS --change-interface=eth1

At this point, you have the opportunity to test your configuration. If these values work for you, you will want to add the same rules to the permanent configuration. You can do that by re-applying the rules with the --permanent flag:
·         sudo firewall-cmd --zone=publicweb --permanent --add-service=ssh
·         sudo firewall-cmd --zone=publicweb --permanent --add-service=http
·         sudo firewall-cmd --zone=publicweb --permanent --add-service=https
·         sudo firewall-cmd --zone=privateDNS --permanent --add-service=dns

You can then modify your network interfaces to automatically select the correct zones.
We can associate the eth0 interface with the "publicweb" zone:
·         sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0
[label /etc/sysconfig/network-scripts/ifcfg-eth0
. . .

IPV6_AUTOCONF=no
DNS1=2001:4860:4860::8844
DNS2=2001:4860:4860::8888
DNS3=8.8.8.8
ZONE=publicweb

And we can associate the eth1 interface with "privateDNS":
·         sudo nano /etc/sysconfig/network-scripts/ifcfg-eth1
/etc/sysconfig/network-scripts/ifcfg-eth1
. . .

NETMASK=255.255.0.0
DEFROUTE='no'
NM_CONTROLLED='yes'
ZONE=privateDNS

Afterwards, you can restart your network and firewall services:
·         sudo systemctl restart network
·         sudo systemctl restart firewalld

Validate that the correct zones were assigned:
·         firewall-cmd --get-active-zones
output
privateDNS
  interfaces: eth1
publicweb
  interfaces: eth0

And validate that the appropriate services are available for both of the zones:
·         firewall-cmd --zone=publicweb --list-services
output
http htpps ssh
·         firewall-cmd --zone=privateDNS --list-services
output
dns

You have successfully set up your own zones. If you want to make one of these zones the default for other interfaces, remember to configure that behavior with the --set-default-zone= parameter:
sudo firewall-cmd --set-default-zone=publicweb


Allowing or Denying an Arbitrary Port/Protocol
As an example: Allow or disable TCP traffic on port 8080.
1
2
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
sudo firewall-cmd --zone=public --remove-port=8080/tcp --permanent

Port Forwarding
The example rule below forwards traffic from port 80 to port 8080 on the same server.
1
sudo firewall-cmd --zone="public" --add-forward-port=port=80:proto=tcp:toport=8080

To forward a port to a different server:

  1. Activate masquerade in the desired zone.
1
sudo firewall-cmd --zone=public --add-masquerade

  1. Add the forward rule. This example forwards traffic from local port 80 to port 8080 on a remote server located at the IP address: 192.168.1.251.
1
sudo firewall-cmd --zone="public" --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=192.168.1.251

To remove the rules, substitute --add with --remove. For example:
1
sudo firewall-cmd --zone=public --remove-masquerade

Advanced Configuration
Services and ports are fine for basic configuration but may be too limiting for advanced scenarios. Rich Rules and Direct Interface allow you to add fully custom firewall rules to any zone for any port, protocol, address and action.
Rich Rules
Rich rules syntax is extensive but fully documented in the firewalld.richlanguage(5) man page (or see man firewalld.richlanguage in your terminal). Use --add-rich-rule--list-rich-rules and--remove-rich-rule with firewall-cmd command to manage them.
Here are some common examples:
Allow all IPv4 traffic from host 192.168.0.14.
1
sudo firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address=192.168.0.14 accept'
Deny IPv4 traffic over TCP from host 192.168.1.10 to port 22.
1
sudo firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="192.168.1.10" port port=22 protocol=tcp reject'
Allow IPv4 traffic over TCP from host 10.1.0.3 to port 80, and forward it locally to port 6532.
1
sudo firewall-cmd --zone=public --add-rich-rule 'rule family=ipv4 source address=10.1.0.3 forward-port port=80 protocol=tcp to-port=6532'
Forward all IPv4 traffic on port 80 to port 8080 on host 172.31.4.2 (masquerade should be active on the zone).
1
sudo firewall-cmd --zone=public --add-rich-rule 'rule family=ipv4 forward-port port=80 protocol=tcp to-port=8080 to-addr=172.31.4.2'
To list your current Rich Rules:
1
sudo firewall-cmd --list-rich-rules

Conclusion
You should now have a fairly good understanding of how to administer the firewalld service on your CentOS system for day-to-day use.
The firewalld service allows you to configure maintainable rules and rule-sets that take into consideration your network environment. It allows you to seamlessly transition between different firewall policies through the use of zones and gives administrators the ability to abstract the port management into more friendly service definitions. Acquiring a working knowledge of this system will allow you to take advantage of the flexibility and power that this tool provides.