Saturday, August 2, 2014

Add Oracle database related services to firewalld

I was setting up data guard environment on Centos 7 machine for testing purposes. Usually I disable iptables firewall at first, but this time firewall stays on and I'll make all necessary holes into it.

TOC

My environment consists of 2 hosts - centos-dg1 and centos-dg2. Each host have two network cards. Eth0 will be used for client connections. Eth1 will be used for dataguard communication. Eth0 cards are plugged to network 192.168.122.0/8 and eth1 cards to 192.168.254.0/8. I will name 192.168.122.0/8 network as public network and 192.168.254.0/8 as internal network. Primary database is named PROD and standby is STPROD.There are 2 listeners on each machine. LISTENER_LOCAL is used for client connections. It is bound to public network. LISTENER_DG is used for Data Guard communication and is bound to internal network. This is how I image communication through firewall:

  • Client connection (e.g. sqlplus) from host to both guests via Oracle Net (TCP:1521)
  • Connection from host to database control on primary database (TCP:1158)
  • Data Guard connections between guests (TCP:1521)

Communication between guests

At first I'll check if it is by any chance working out of the box. I've started listeners on the first guest, the are bound to correct addresses and ports:

[oracle@centos-dg1 PROD ~]$ sudo netstat -tnlp | grep 1521
tcp        0      0 192.168.254.10:1521     0.0.0.0:*               LISTEN      3234/tnslsnr        
tcp        0      0 192.168.122.175:1521    0.0.0.0:*               LISTEN      3229/tnslsnr        

First line belongs to the LISTENER_LOCAL and second to the LISTENER_DG. I'll try to tnsping both listeners from first guest:

[oracle@centos-dg1 PROD ~]$ tnsping LISTENER_LOCAL
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg1.localdomain)(PORT = 1521)(IP = FIRST)))
OK (0 msec)
[oracle@centos-dg1 PROD ~]$ tnsping LISTENER_DG
.
.
.
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg1-dg.localdomain)(PORT = 1521)(IP = FIRST)))
OK (0 msec)

Working. But it is no surprise because I'm connecting to the same machine where I'm logged in. This kind of communication is usually allowed. I'll try it from other guest:

[oracle@centos-dg2 STPROD ~]$ tnsping PROD
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg1.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = PROD.LOCALDOMAIN)))
TNS-12543: TNS:destination host unreachable
[oracle@centos-dg2 STPROD ~]$ tnsping PROD_DG
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg1-dg.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = PROD.LOCALDOMAIN)))
TNS-12543: TNS:destination host unreachable

Error message means that communication is not allowed to pass through the firewall.

Network separation

I will look at zones. I can see only one active zone:

[root@centos-dg1 ~]# firewall-cmd --get-active-zones 
public
  interfaces: eth0 eth1

Public zone contains both interfaces which I don't like. I want to create internal zone with eth1 interface. Here it comes:

[root@centos-dg1 ~]# firewall-cmd --get-active-zones
public
  interfaces: eth0 eth1
[root@centos-dg1 ~]# firewall-cmd --zone=public --remove-interface=eth1
success
[root@centos-dg1 ~]# firewall-cmd --zone=public --remove-interface=eth1 --permanent
success
[root@centos-dg1 ~]# firewall-cmd --zone=internal --add-interface=eth1
success
[root@centos-dg1 ~]# firewall-cmd --zone=internal --add-interface=eth1 --permanent
success
[root@centos-dg1 ~]# firewall-cmd --get-active-zones 
internal
  interfaces: eth1
public
  interfaces: eth0

Now I have two zones as I like it - public network interface in public zone and internal network interface in internal zone.

Define firewalld service for oracle database

I need to tell firewalld that it should kindly allow communication to TCP:1521 between guest machines. I'll define firewalld services:

[root@centos-dg1 ~]# cat /tmp/oracledb.xml 
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>OracleDB</short>
  <description>Service for connection to Oracle database. If you plan to provide a database connection on this host, enable this option.</description>
  <port protocol="tcp" port="1521"/>
</service>

I'll move this file to /etc/firewalld/services where all user defined services belongs. I'll not forget to set correct privileges and selinux context:

[root@centos-dg1 ~]# mv /tmp/oracledb.xml  /etc/firewalld/services/
[root@centos-dg1 ~]# ls -lZ /etc/firewalld/services/oracledb.xml 
-rw-r--r--. root root system_u:object_r:firewalld_etc_rw_t:s0 /etc/firewalld/services/oracledb.xml

After reloading firewalld I can see oracledb among services:

[root@centos-dg1 ~]# systemctl reload firewalld.service 
[root@centos-dg1 ~]# firewall-cmd --get-services
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 oracledb 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

I'll print which services are allowed in internal zone.

[root@centos-dg1 ~]# firewall-cmd --list-services --zone=internal 
dhcpv6-client ipp-client mdns samba-client ssh

No oracledb service there! I have to add service oracledb to internal zone:

[root@centos-dg1 ~]# firewall-cmd --list-services --zone=internal
dhcpv6-client ipp-client mdns samba-client ssh
[root@centos-dg1 ~]# firewall-cmd --add-service=oracledb --zone=internal 
success
[root@centos-dg1 ~]# firewall-cmd --add-service=oracledb --zone=internal --permanent
success
[root@centos-dg1 ~]# firewall-cmd --list-services --zone=internal 
dhcpv6-client ipp-client mdns oracledb samba-client ssh

Connection from second guest to the first guest's internal network (guest2 -> guest1:internal network:1521) should work now:

[oracle@centos-dg2 STPROD ~]$ tnsping PROD_DG
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg1-dg.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = PROD.LOCALDOMAIN)))
OK (10 msec)

I will run same commands on the other guest in order to achieve same goal (guest1 -> guest2:internal network:1521):

[root@centos-dg2 ~]# scp centos-dg1:/etc/firewalld/services/oracledb.xml /etc/firewalld/services/
oracledb.xml                                  100%  274     0.3KB/s   00:00    
[root@centos-dg2 ~]# chcon -u system_u /etc/firewalld/services/oracledb.xml 
[root@centos-dg2 ~]# systemctl reload firewalld.service 
[root@centos-dg2 ~]# firewall-cmd --zone=public --remove-interface=eth1
success
[root@centos-dg2 ~]# firewall-cmd --zone=public --remove-interface=eth1 --permanent
success
[root@centos-dg2 ~]# firewall-cmd --zone=internal --add-interface=eth1
success
[root@centos-dg2 ~]# firewall-cmd --zone=internal --add-interface=eth1 --permanent
success
[root@centos-dg2 ~]# firewall-cmd --add-service=oracledb --zone=internal
success
[root@centos-dg2 ~]# firewall-cmd --add-service=oracledb --zone=internal --permanent
success
[root@centos-dg2 ~]#  firewall-cmd --list-services --zone=internal
dhcpv6-client ipp-client mdns oracledb samba-client ssh

I'll check Oracle Net connection from this direction:

[root@centos-dg1 ~]# tnsping STPROD_DG
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg2-dg.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = STPROD.LOCALDOMAIN)))
OK (10 msec)

Communication from host to guests

I want to log into databases from host. I'll check whether communication is allowed or not:

[vajko@kra ~]$ tnsping PROD
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg1.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = PROD.LOCALDOMAIN)))
TNS-12543: TNS:destination host unreachable
[vajko@kra ~]$ tnsping STPROD
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg2.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = STPROD.LOCALDOMAIN)))
TNS-12543: TNS:destination host unreachable

Communication is denied by firewall again. Adding oracledb service to public zone on both guests will solve the problem:

[root@centos-dg1 ~]# firewall-cmd --add-service=oracledb --zone=public 
success
[root@centos-dg1 ~]# firewall-cmd --add-service=oracledb --zone=public --permanent
success

[root@centos-dg2 ~]# firewall-cmd --add-service=oracledb --zone=public
success
[root@centos-dg2 ~]# firewall-cmd --add-service=oracledb --zone=public --permanent
success

And check:

[vajko@kra ~]$ tnsping PROD
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg1.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = PROD.LOCALDOMAIN)))
OK (0 msec)
[vajko@kra ~]$ tnsping STPROD
.
.
.
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = centos-dg2.localdomain)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = STPROD.LOCALDOMAIN)))
OK (0 msec)

Working as advertised. Last thing which needs to be checked is database console.

Define firewalld service for oracle database console

I'll start database console and check to which interface it is bound:

[oracle@centos-dg1 PROD ~]$ emctl start dbconsole
Oracle Enterprise Manager 11g Database Control Release 11.2.0.3.0 
Copyright (c) 1996, 2011 Oracle Corporation.  All rights reserved.
http://centos-dg1:1158/em/console/aboutApplication
Starting Oracle Enterprise Manager 11g Database Control .... started. 
------------------------------------------------------------------
Logs are generated in directory /u01/app/oracle/product/11.2.0/db_1/centos-dg1_PROD/sysman/log 
[oracle@centos-dg1 PROD ~]$ netstat -tnlp | grep 1158
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp6       1      0 :::1158                 :::*                    LISTEN      3553/java     

Database console is running and bound to all interfaces which I don't mind. I'll try to connect from host:

[vajko@kra ~]$ telnet centos-dg1 1158
Trying 192.168.122.175...
telnet: connect to address 192.168.122.175: No route to host

It is denied as expected. Therefore I will define firewalld service for database console:

[root@centos-dg1 ~]# cat /tmp/oracledbconsole.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Oracle database console</short>
  <description>Bla bla bla oracle db console bla bla bla</description>
  <port protocol="tcp" port="1158"/>
</service>

I'll move it to correct location and reload firewalld:

[root@centos-dg1 ~]# mv /tmp/oracledbconsole.xml /etc/firewalld/services/
[root@centos-dg1 ~]# ls -lZ /etc/firewalld/services/oracledbconsole.xml 
-rw-r--r--. root root system_u:object_r:firewalld_etc_rw_t:s0 /etc/firewalld/services/oracledbconsole.xml
[root@centos-dg1 ~]# systemctl reload firewalld.service 

I'll add oracledbconsole service to public zone:

[root@centos-dg1 ~]# firewall-cmd --add-service=oracledbconsole --zone=public 
success
[root@centos-dg1 ~]# firewall-cmd --add-service=oracledbconsole --zone=public --permanent
success

Now I can finally connect to database console from host:

[vajko@kra ~]$ telnet centos-dg1 1158
Trying 192.168.122.175...
Connected to centos-dg1.
Escape character is '^]'.

How to enable communication to database console on second guest (in case of switchover or failover)? I will kindly leave it as excercise to reader.

No comments:

Post a Comment