Hero Image
Backup FortiOS config with Ansible - with RestAPI

Fortigate RestAPI Config Backup - FortiOS 6.0.4 Backup FortiOS config with Ansible - with RestAPI Create access profile FGTAWS0004BE1ADE # config system accprofile FGTAWS0004BE1ADE (accprofile) # edit readOnly new entry 'readOnly' added FGTAWS0004BE1ADE (readOnly) # set sysgrp read FGTAWS0004BE1ADE (readOnly) # end Create API user in Fortigate FGTAWS0004BE1ADE # config system api-user FGTAWS0004BE1ADE (api-user) # edit api-admin new entry 'api-admin' added FGTAWS0004BE1ADE (api-admin) # set accprofile "readOnly" FGTAWS0004BE1ADE (api-admin) # set vdom root FGTAWS0004BE1ADE (api-admin) # config trusthost FGTAWS0004BE1ADE (trusthost) # edit 1 new entry '1' added FGTAWS0004BE1ADE (1) # set ipv4-trusthost 'ip_address_of_your_machine' 255.255.255.255 FGTAWS0004BE1ADE (1) # end FGTAWS0004BE1ADE (api-admin) # end Generate API token FGTAWS0004BE1ADE # execute api-user generate-key api-admin New API key: 'your_api_token' NOTE: The bearer of this API key will be granted all access privileges assigned to the api-user api-admin. Test # fortigate.py import requests import urllib3 # disable security warning for SSL certificate urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # disable security warning for SSL certificate def config_download(ipaddr, api_token, filename='backup.conf'): ''' input: ipaddr(string) - target ip address of fortigate input: api_token(string) - api_token for api user(accprofile should have sysgrp.mnt) input: filename(string) - file name of the config to be saved. default backup.conf output: True if backup successfule. False if not successful. Tested on: Fortigate OnDemand on AWS - FortiOS6.0.4 ''' base_url = f'https://{ipaddr}/api/v2/' headers = {'Authorization': f'Bearer {api_token}'} params = {'scope': 'global'} uri = 'monitor/system/config/backup/' rep = requests.get(base_url + uri, headers=headers, params=params, verify=False) if rep.status_code != 200: print(f'Something went wrong. status_code: {rep.status_code}') return False with open(filename, 'w') as f: f.write(rep.text) return True >>> import fortigate >>> >>> ip_addr = 'Fortigate_IP_Address' >>> api_token = 'API_TOKEN' >>> >>> if (fortigate.config_download(ip_addr, api_token, 'backup20190215.conf')): ... print('Done!') ... else: ... print('Error!!') ... Done! >>> >>> with open('backup20190215.conf', 'r') as f: ... f.readline() ... '#config-version=FGTAWS-6.0.4-FW-build0231-190107:opmode=0:vdom=0:user=api-admin\n' >>> Configure Ansible inventory and playbook $ cat hosts [fortigate] x.x.x.x access_token=w4q9qtfbGry3Nbc40kHjsk9mxG**** y.y.y.y access_token=tfy8c9b8Nxw6N3Q5Q5bg9z69dn**** $ cat fortigate_backup.yml - name: fortigate config backup connection: local hosts: fortigate tasks: - name: get current config uri: url: 'https://{{ ansible_host }}/api/v2/monitor/system/config/backup/?scope=global&access_token={{ access_token }}' return_content: yes validate_certs: no register: current_config - name: write config to local file local_action: copy content={{ current_config.content }} dest=./{{ inventory_hostname }}_{{ ansible_date_time.date }}.txt

Hero Image
Hero Image
Nginx HTTPS with Basic Auth reverse proxy for VMware ESXi 6.5 fixed VMRC /screen

Nginx HTTPS with Basic Auth reverse proxy for VMware ESXi 6.5 fixed VMRC /screen server { listen 80; server_name esxi.hackion.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl; server_name esxi.hackion.com; ssl_certificate /mycert.crt; ssl_certificate_key /mykey.key; location / { auth_basic "Restricted Content"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_set_header Upgrade $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Origin ''; proxy_set_header Authorization ''; #Don't pass the Nginx Basic Auth to ESXi or it will break VMRC. proxy_pass_header X-XSRF-TOKEN; proxy_pass https://esxi_server; proxy_send_timeout 300; proxy_read_timeout 300; send_timeout 300; client_max_body_size 1000m; # enables WS support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } server { listen 443 ssl http2; # ssl_certificate and ssl_certificate_key are required ssl_certificate /etc/letsencrypt/live/myletsencryptdomain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/myletsencryptdomain/privkey.pem; include /etc/nginx/snippets/ssl-params.conf; # removed DH params as my ssl-params.conf specifies to only use ECDHE key exchange. server_name fqdn.extern; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_ssl_verify off; # No need on isolated LAN proxy_pass https://vcenter.ip; # esxi IP Address proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_buffering off; client_max_body_size 0; proxy_read_timeout 36000s; proxy_redirect https://fqdn.local/ https://fqdn.extern/; # read comment below # replace vcenter-hostname with your actual vcenter's hostname, and esxi with your nginx's server_name. } location /websso/SAML2 { proxy_set_header Host fqdn.local; # your actual vcenter's hostname proxy_set_header X-Real-IP $remote_addr; proxy_ssl_verify off; # No need on isolated LAN proxy_pass https://vcenter.ip; # esxi IP Address proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_buffering off; client_max_body_size 0; proxy_read_timeout 36000s; proxy_ssl_session_reuse on; proxy_redirect https://fqdn.local/ https://fqdn.extern/; # read comment below # replace vcenter-hostname with your actual vcenter's hostname, and esxi with your nginx's server_name. } }

Hero Image
Vagrantfile and Provider

Day 8 - Vagrantfile and Provider Day 9 - Advanced Vagrantfile(編輯中) 用以下這個範例 你只要使用 Vagrant up 加上 provider 參數,就可開啟不同來源的機器 例如我要開啟 Vsphere 的機器,我只要下 vagrant up --provider=vsphere 要開 AWS 的機器,我只要下 vagrant up --provider=aws VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # 我們定義一個 Ubuntu 的機器 # box 的需求是對於 local 的 VM 才需要的 # 所以在 provider 是 vmware_fusion 或 Virtualbox 時,才會用到這個設定 config.vm.box = "hashicorp/precise64" # vmware_fusion config.vm.provider "vmware_fusion" do |v, override| override.vm.box = "precise64_vmware" v.gui = false end # vsphere config.vm.provider :vsphere do |vsphere| # 對於私有雲及公有雲,要clone 的vm 是儲存在雲端上的 # 所以 box 使用 dummy box 來達到這個目的 vsphere.vm.box = "nkhasanov/vsphere-simple" vsphere.host = 'YOURIP' vsphere.compute_resource_name = 'YOUR DATACENTER' vsphere.resource_pool_name = 'YOUR RESOURCE POOL' vsphere.insecure = true vsphere.template_name = 'VM TEMPLATE' vsphere.name = "#{YOUR_NAME}-test-machine" vsphere.user = 'administrator' vsphere.password = '$p1unK_Lab' vsphere.vm_base_path = 'vmware_template' vsphere.linked_clone = true end # virtual box config.vm.provider "virtualbox" do |vb| vb.gui = false end # aws config.vm.provider :aws do |aws, override| # aws configurations aws.access_key_id = "#{YOUR_AWS_ACCESS_KEY_ID}" aws.secret_access_key = "#{YOUR_AWS_ACCESS_KEY}" aws.keypair_name = "#{YOUR_NAME}" aws.security_groups = "#{YOUR_NAME}" aws.instance_type = "t2.small" aws.region = "us-east-1" # ubuntu 14.04 x64 aws.ami = "ami-864d84ee" # override info override.ssh.username = "ubuntu" override.ssh.private_key_path = "#{YOUR_AWS_PRIVATE_KEY_PATH}" override.vm.synced_folder "#{YOUR_SYNC_FOLDER}", "/vagrant", type: "rsync" override.vm.box = "dimroc/awsdummy" end end LOCAL_BOXS = { "ubuntu1404x64" => "ubuntu/trusty64", "ubuntu1210x64" => "chef/ubuntu-12.10" } AWS_AMIS = { "ubuntu1404x64" => "ami-864d84ee", "ubuntu1210x64" => "ami-02df496b", "windows2012r2x64" => "ami-9ade1df2", "windows2012x64" => "ami-5ce32034", "windows2008r2x64" => "ami-2ae02342", "windows2008x64" => "ami-5e24e936", "windows2003r2x64" => "ami-b0e320d8" } VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "precise64_vmware" # vmware_fusion config.vm.provider "vmware_fusion" do |v, override| override.vm.box = "precise64_vmware" v.gui = false v.vmx["memsize"] = "1024" v.vmx["numvcpus"] = "2" end # vsphere config.vm.provider :vsphere do |vsphere| vsphere.vm.box = "nkhasanov/vsphere-simple" vsphere.host = '#{}' vsphere.compute_resource_name = '#{}' # vsphere.resource_pool_name = 'YOUR RESOURCE POOL' vsphere.insecure = true vsphere.template_name = 'qasus-tw-centos7x64-01' vsphere.name = "#{YOUR_NAME}-test-machine" vsphere.user = 'administrator' vsphere.password = '#{}' vsphere.vm_base_path = 'vmware_template' vsphere.linked_clone = true end # virtual box config.vm.provider "virtualbox" do |vb| vb.gui = false vb.memory = 1024 vb.cpus = 2 end # aws config.vm.provider :aws do |aws, override| # aws configurations aws.access_key_id = "#{YOUR_AWS_ACCESS_KEY_ID}" aws.secret_access_key = "#{YOUR_AWS_ACCESS_KEY}" aws.keypair_name = "#{YOUR_NAME}" aws.security_groups = "#{YOUR_NAME}" aws.instance_type = "t2.small" aws.region = "us-east-1" # ubuntu 14.04 x64 aws.ami = "ami-864d84ee" # override info override.ssh.username = "ubuntu" override.ssh.private_key_path = "#{YOUR_AWS_PRIVATE_KEY_PATH}" override.vm.synced_folder "#{YOUR_SYNC_FOLDER}", "/vagrant", type: "rsync" override.vm.box = "dimroc/awsdummy" end # VMs (1..MAX_VM_NUMBER).each do |i| # define linux config.vm.define "l#{i}" do |node| # aws node.vm.provider :aws do |aws| aws.tags = { "Name" => "#{YOUR_NAME}-linux-#{i}" } end # local # node.vm.network "private_network", ip: "192.168.33.%d" % (i+2) node.vm.hostname = "ftan-linux-#{i}" end # define windows config.vm.define "w#{i}" do |node| node.vm.provider :aws do |aws| aws.ami = "ami-2ae02342" aws.tags = { "Name" => "#{YOUR_NAME}-windows-#{i}" } end end end # define customer YOUR_CUSTOMIZED_VM.each do |vm| config.vm.define "%s" % vm["name"] do |node| # aws node.vm.provider :aws do |aws| aws.ami = AWS_AMIS[vm["platform"]] aws.tags = { "Name" => "#{YOUR_NAME}-%s" % vm["name"] } end # vmware fusion # vmware workstation node.vm.provider :vmware_fusion do |fusion| fusion.vm.box = LOCAL_BOXS[vm["platform"]] fusion.vm.hostname = "#{YOUR_NAME}-%s" % vm["name"] end # vsphere # azure end end end

Hero Image
How to configure time zone and NTP on RHEL7/CentOS7

How to configure time zone and NTP on RHEL7/CentOS7 chrony includes two programs: chronyd is a daemon that starts on boot, and chronyc is a command-line client that can monitor chronyd and change runtime parameters. Use either ntpd or chronyd, not both. Configure time zone ~# timedatectl set-timezone Asia/Taipei ~# timedatectl Local time: Tue 2018-03-27 14:13:38 CST Universal time: Tue 2018-03-27 06:13:38 UTC RTC time: Tue 2018-03-27 06:13:40 Time zone: Asia/Taipei (CST, +0800) NTP enabled: no NTP synchronized: no RTC in local TZ: no DST active: n/a Configure chronyd # Install ~# yum install -y chrony # Config file ~# cat /etc/chrony.conf # Use public servers from the pool.ntp.org project. # Please consider joining the pool (http://www.pool.ntp.org/join.html). server 0.tw.pool.ntp.org iburst --->改成本地的伺服器 server 1.tw.pool.ntp.org iburst --->改成本地的伺服器 server 2.tw.pool.ntp.org iburst --->改成本地的伺服器 server 3.tw.pool.ntp.org iburst --->改成本地的伺服器 # Start service and enable on boot ~# systemctl enable chronyd ~# systemctl start chronyd tracking parameters show system time performance ~# chronyc tracking Reference ID : 3DD8996B (61-216-153-107.hinet-ip.hinet.net) --->表示現在同步的時間伺服器,如果沒有id表示沒有同步 Stratum : 4 --->表示計算機有多少"跳hop" 表示本地的是第四層 Ref time (UTC) : Tue Mar 27 06:03:38 2018 --->最後一次測量的時間 System time : 0.000040356 seconds fast of NTP time --->調整系統時間 Last offset : +0.000163738 seconds RMS offset : 0.000163738 seconds Frequency : 21.384 ppm fast Residual freq : +0.000 ppm Skew : 675.319 ppm Root delay : 0.008527911 seconds Root dispersion : 0.066466033 seconds Update interval : 2.0 seconds Leap status : Normal --->Normal要顯示此值, Insert second, Delete second or Not synchronised. ~# chronyc sources -v 210 Number of sources = 4 .-- Source mode '^' = server, '=' = peer, '#' = local clock. / .- Source state '*' = current synced, '+' = combined , '-' = not combined, | / '?' = unreachable, 'x' = time may be in error, '~' = time too variable. || .- xxxx [ yyyy ] +/- zzzz || Reachability register (octal) -. | xxxx = adjusted offset, || Log2(Polling interval) --. | | yyyy = measured offset, || \ | | zzzz = estimated error. || | | \ MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== ^* 59-124-29-241.hinet-ip.h> 3 6 37 24 -1462us[-2363us] +/- 49ms ^+ 61-216-153-107.hinet-ip.> 3 6 37 23 -556us[ -556us] +/- 64ms ^? 59-125-122-217.hinet-ip.> 0 7 0 - +0ns[ +0ns] +/- 0ns ^- 61-216-153-105.hinet-ip.> 3 6 37 23 -280us[ -280us] +/- 64ms View sync source info ~# chronyc sourcestats -v 210 Number of sources = 4 .- Number of sample points in measurement set. / .- Number of residual runs with same sign. | / .- Length of measurement set (time). | | / .- Est. clock freq error (ppm). | | | / .- Est. error in freq. | | | | / .- Est. offset. | | | | | | On the -. | | | | | | samples. \ | | | | | | | Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev ============================================================================== 59-124-29-241.hinet-ip.h> 6 5 135 -0.454 4.553 -784us 66us 61-216-153-107.hinet-ip.> 6 6 135 +4.455 19.761 +622us 247us 59-125-122-217.hinet-ip.> 0 0 0 +0.000 2000.000 +0ns 4000ms 61-216-153-105.hinet-ip.> 6 4 136 +8.965 42.440 +1250us 495us Write system time to hardware clock ~# hwclock --systohc ~# date ; hwclock Tue Mar 27 14:07:57 CST 2018 Tue 27 Mar 2018 02:07:58 PM CST -0.938012 seconds

Hero Image
Install PowerDNS and PowerDNS-Admin on Ubuntu 22.04|20.04|18.04

Install PowerDNS and PowerDNS-Admin on Ubuntu 22.04|20.04|18.04 Master-Master PowerDNS with Galera Replication https://www.scaleway.com/en/docs/installing-powerdns-server-on-ubuntu-bionic/ Install PowerDNS $ sudo apt update $ sudo apt install mariadb-server -y $ sudo mysql -u root CREATE DATABASE powerdns; GRANT ALL ON powerdns.* TO 'powerdns'@'localhost' IDENTIFIED BY 'Str0ngPasswOrd'; FLUSH PRIVILEGES; USE powerdns; CREATE TABLE domains ( id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL, master VARCHAR(128) DEFAULT NULL, last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial INT UNSIGNED DEFAULT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX name_index ON domains(name); CREATE TABLE records ( id BIGINT AUTO_INCREMENT, domain_id INT DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, type VARCHAR(10) DEFAULT NULL, content VARCHAR(64000) DEFAULT NULL, ttl INT DEFAULT NULL, prio INT DEFAULT NULL, change_date INT DEFAULT NULL, disabled TINYINT(1) DEFAULT 0, ordername VARCHAR(255) BINARY DEFAULT NULL, auth TINYINT(1) DEFAULT 1, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX nametype_index ON records(name,type); CREATE INDEX domain_id ON records(domain_id); CREATE INDEX ordername ON records (ordername); CREATE TABLE supermasters ( ip VARCHAR(64) NOT NULL, nameserver VARCHAR(255) NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (ip, nameserver) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE TABLE comments ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(10) NOT NULL, modified_at INT NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, comment TEXT CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX comments_name_type_idx ON comments (name, type); CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); CREATE TABLE domainmetadata ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, kind VARCHAR(32), content TEXT, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind); CREATE TABLE cryptokeys ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, flags INT NOT NULL, active BOOL, content TEXT, PRIMARY KEY(id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainidindex ON cryptokeys(domain_id); CREATE TABLE tsigkeys ( id INT AUTO_INCREMENT, name VARCHAR(255), algorithm VARCHAR(50), secret VARCHAR(255), PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); $ sudo systemctl disable systemd-resolved $ sudo systemctl stop systemd-resolved $ ls -lh /etc/resolv.conf lrwxrwxrwx 1 root root 39 Jul 24 15:50 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf $ sudo unlink /etc/resolv.conf $ echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf Add official PowerDNS repository for Ubuntu 22.04|20.04|18.04.