Thứ Hai, 13 tháng 6, 2022

Sử dụng Chrony

 Nguồn: 

https://legitwhiz.github.io/technology_memo/What_changed_to_chrony_instead_of_NTP.html

https://kita-san.blog/computer-related/chrony-ntp/

Phần 1. Chrony CLIENT

1.1 Cấu hình

1.2 Kiểm tra các Source NTP đã khai báo

[root@node-1 ~]# chronyc sources

210 Number of sources = 4

MS Name/IP address         Stratum Poll Reach LastRx Last sample

===============================================================================

^+ time.cloudflare.com           3  10   377   383   +257us[ +257us] +/-   75ms

^+ time.cloudflare.com           3  10   377   612  +1732us[+1917us] +/-   74ms

^- 203.113.174.44                3   8   377    88    -10ms[  -10ms] +/-  199ms

^* ntp1.tino.org                 3  10   377   550  -1690us[-1504us] +/-   56ms

1.3 Kiểm tra server hiện tại lệch với NTP server bao nhiêu giây

 [root@node-1 ~]# chronyc tracking

Reference ID    : 6782D929 (ntp1.tino.org)

Stratum         : 4

Ref time (UTC)  : Sat Jul 08 03:25:15 2023 (Đây là thời gian NTP server cung cấp)

System time     : 615026.687500000 seconds slow of NTP time

(Đây chính là thời gian chậm hoặc lệch so với NTP Server)

Last offset     : +0.000186317 seconds

RMS offset      : 38011.906250000 seconds

Frequency       : 7.449 ppm fast

Residual freq   : +0.004 ppm

Skew            : 0.206 ppm

Root delay      : 0.061822563 seconds

Root dispersion : 0.025475020 seconds

Update interval : 482.0 seconds

Leap status     : Normal

 

 

1.4 Fource update with slew mode

chronyc -a 'burst 4/4'

 

1.5 Force update time NOW

# chronyc -a makestep

 

 

Phần 2. Chrony Server

2.1 bật chrony server

# vi /etc/chrony.conf 
pool xxx.xxx.xxx.xxx
stratumweight 0
driftfile /var/lib/chrony/drift
rtcsync
leapsecmode slew
 
deny all
allow 192.168.120
bindaddress 127.0.0.1
bindcmdaddress ::1
local stratum 10
 
#noclientlog
logchange 0.5
logdir /var/log/chrony

 

 

2.2 Kiểm tra có những client nào đang kết nối vào NTP server

# chronyc -a clients



Thứ Năm, 21 tháng 4, 2022

Kurbernetes Network Policy

 

Tại sao chúng ta phải dùng NetworkPolicy:

  • Allow đến mức pod gọi pod, giới hạn pod gọi internet. Tránh trường hợp 1 pod bị chiếm quyền tấn công loạn xạ toàn bộ hệ thống k8s.

Để hiểu cơ bản về việc các pod gọi nhau trong k8s, ta sẽ đi P1 và P2 khi chưa có chặn networkpolicies. Và P3,P4 sẽ thực hiện chặn lại.

Phần 1: Pod gọi Pod - cùng Namespace:

Phần này ta tạo 2 pod nằm trong cùng 1 NS, sau đó thực hiện gọi nhau thông qua service_name

# kubectl create ns tuanda0
# kubectl -n tuanda0 run --image=nginx web01
# kubectl -n tuanda0 expose pod web01 --port=80
# kubectl -n tuanda0 run busybox --image=busybox --restart=Never -- /bin/sh -c 'echo hello;sleep 36000'
Thực hiện kiểm tra bằng việc truy cập busybox và gọi service_name nginx
# kubectl -n tuanda0 exec -it busybox -- /bin/sh
> wget web01
    Hello World

Phần 2: Pod gọi Pod - khác Namespace

Phần này ta tạo 2 pod nằm khác NS, Để gọi chéo ta thêm tiền tố namespace sau service_name :

<svcname>.<namespace>.svc.cluster.local hoặc rút gọn: <svcname>.<namespace>


kubectl create ns tuanda1
kubectl create ns tuanda2
kubectl -n tuanda1 run --image=nginx web01
kubectl -n tuanda1 expose pod web01 --port=80
kubectl -n tuanda2 run busybox --image=busybox --restart=Never -- /bin/sh -c 'echo hello;sleep 36000'
# Ta thực hiện vào pod2 (ns: tuanda2) để kiểm tra thông với pod1 ở ns tuanda1
kubectl -n tuanda2 exec -it busybox -- /bin/sh
> nslookup web01.tuanda1.svc.cluster.local   [OK]
> wget web01.tuanda1.svc.cluster.local
    Hello World

Phần 3: Pod gọi nhau sử dụng Networkpolicies Deny all - cùng NameSpace

Chuẩn bị pod và ns để test:

kubectl create ns frontend
kubectl label namespaces frontend role=frontend --overwrite=true
kubectl -n frontend run --image=nginx --labels="app=web_frontend" nginx
kubectl -n frontend expose pod nginx --port=80
kubectl -n frontend run busybox --image=busybox --restart=Never -- /bin/sh -c 'echo hello;sleep 36000'

Step1: DENY ALL

Việc đầu tiên phải làm là ta cần deny all và mở những rule cần thiết ở các VD tiếp.

# vim 01.deny-frontend.yaml
    
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: frontend
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Kết quả:


Case1 : Allow Egress (outbound)

Trong case này, ta giả lập cần mở cho busybox gọi ra ngoài web google, api sendmail, api sms....


# kubectl get ns --show-labels (để lấy label của namespace)
# kubectl get all -n frontend --show-labels (để lấy label của pod)
# vim 02.allow-http-dns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-http-dns
  namespace: frontend
spec:
  policyTypes:
  - Egress
  podSelector: {} 
  egress:
  - ports:
    - port: 53
      protocol: UDP
    - port: 80
      protocol: TCP
    - port: 443
      protocol: TCP
    
Vào pod busybox thực hiện wget google.com KQ: [return 200]. Với trường hợp ta chỉ định pod nhất định > thì có thể sửa podSelector:
  podSelector:
    matchLabels:
      role: db
Ngoài ra có thể giới hạn chính xác IP được gọi, chứ ko mở all 80/443 ra ngoài như sau:
  egress:   
  - to:     
    - ipBlock:         
        cidr: 123.123.68.68/32
    ports:     
    - protocol: TCP       
      port: 8080

Case2: Allow Ingress (Inbound)

Vậy với trường hợp Pod gọi Pod khi bị DenyAll, ta thực hiện như sau:


# kubectl get ns --show-labels (để lấy label của namespace)
# kubectl get all -n frontend --show-labels (để lấy label của pod)

# vim 03.allow-http-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: 03-allow-http-ingress
  namespace: frontend
spec:
  podSelector:
    matchLabels:
      app: web_frontend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          role: frontend
      podSelector:
        matchLabels:
          run: busybox
    ports:
    - protocol: TCP
      port: 80

# kubectl apply  -f 03.allow-http-ingress.yaml
# kubectl -n frontend exec -it busybox -- sh  (vào pod busybox để kiểm tra)
> wget nginx 
Hello World
    

Phần 4: Pod gọi nhau sử dụng Networkpolicies Deny all - khác NameSpace

Xóa ns để tạo lại môi trường giả lập

kubectl delete ns frontend
kubectl delete ns backend

kubectl create ns frontend
kubectl label namespaces frontend role=frontend --overwrite=true
kubectl -n frontend run --image=nginx --labels="app=web_frontend" nginx
kubectl -n frontend expose pod nginx --port=80
kubectl -n frontend run busybox --image=busybox --restart=Never -- /bin/sh -c 'echo hello;sleep 36000'

kubectl create ns backend
kubectl label namespaces backend role=backend --overwrite=true
kubectl -n backend run --image=nginx --labels="app=web_backend" nginx
kubectl -n backend expose pod nginx --port=80
kubectl -n backend run busybox --image=busybox --restart=Never -- /bin/sh -c 'echo hello;sleep 36000'

Sơ đồ 



**B1: Chặn toàn bộ network 2 ns là frontend và backend **

#vim  01.deny-frontend.yaml 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: 01-default-deny-all-frontend
  namespace: frontend
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

# vim 01.deny-backend.yaml 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: 01-default-deny-all-backend
  namespace: backend
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
# kubectl apply  -f 01.deny-backend.yaml 
# kubectl apply  -f 01.deny-frontend.yaml 

B2: Mở exgress cho Frontend DNS + OutBound

(1, ====Vì busybox cần biết IP của service_backend là bao nhiêu, nên ta cần mở DNS 53====)
#  vim 05.exgress-frontend-allow-dns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: exgress-frontend-allow-dns
  namespace: frontend
spec:
  podSelector:
    matchLabels:
      run: busybox
  policyTypes:
  - Egress
  egress:
  - ports:
    - port: 53
      protocol: UDP
    
(====================2, Mở Egress cho Frontend ====================)
# vim 06.exgress-frontend-allow-http.yaml 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: exgress-frontend-allow-http
  namespace: frontend
spec:
  podSelector:
    matchLabels:
      run: busybox
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          role: backend
      podSelector:
        matchLabels:
          app: web_backend

B3: Mở ingress ở Backend cho phép frontend gọi vào

(====================3, Mở Ingress cho Backend ====================)
07.ingress-backend-allow-http.yaml 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-backend-allow-http
namespace: backend
spec:
podSelector:
  matchLabels:
    app: web_backend
policyTypes:
- Ingress
ingress:
- from:
  - namespaceSelector:
      matchLabels:
        role: frontend
    podSelector:
      matchLabels:
        run: busybox
  ports:
  - protocol: TCP
    port: 80

(====================Test ====================)    
kubectl -n frontend exec -it busybox -- sh
> wget nginx.backend
  HelloWorld

Tổng kết: Mô hình mô phỏng kết nối của Front - Back - DB sẽ như dưới đấy, ta sẽ dựa vào exgress và ingress để mở toàn bộ kết nối


Nguồn tham khảo:

https://kubernetes.io/docs/concepts/services-networking/network-policies/

https://faun.pub/debugging-networkpolicy-part-1-249921cdba37

https://pauldally.medium.com/debugging-networkpolicy-part-2-2d5c42d8465c

https://docs.giantswarm.io/getting-started/network-policies/

Thứ Sáu, 18 tháng 3, 2022

Ansible Cheat Sheet


Vim config fast Ansible

# vim ~/.vimrc 
set ts=2 sw=2
set tabstop=2

Inventory

[redis_server]
pc1 ansible_ssh_host=192.168.122.129 install_redis=yes  redis_role=master
pc2 ansible_ssh_host=192.168.122.128 install_redis=yes  redis_role=slave
pc3 ansible_ssh_host=192.168.122.129 install_redis=yes  redis_role=slave

Roles

Khai báo roles

---
- name: Install redis
  hosts: redis
  vars:
    - ahihi: 'kaka'
  
  roles:
    - role: redis-all-in-one
      become: true

Folder and File

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html

- name: create folder
  file:
    path: /setup
    state: directory #hoặc file
    owner: foo
    group: foo
    mode: '0755'
    
- name: delete folder
  file:
    path: /setup
    state: absent

Debug

- name: show echo
  shell: echo {{ tuanda }}
  register: kiemtra

- name: Debug kiem tra lan 1
  debug:
    var: kiemtra

- name: debug kiem tra lan 2
  debug:
    msg: XIN CHAO {{ kiemtra }}

Tags

Để gọi riêng từng nhóm tags, đỡ phải chạy task không cần thiết như make redis (bỏ). Ta gọi thẳng start redis

Variable Priority

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#understanding-variable-precedence cái nào xuất hiện trước, sẽ được ưu tiên lấy ra đầu tiên

1. File trong yml role > inventory /etc/ansible/hosts
- option -e cao nhất (0)
- Khai báo trong thư mục roles/xxx/vars (1) sẽ có độ ưu tiên cao nhất, dù khai báo 2,3,4 đều không lấy biến đó.
- file role tổng (2) (file gọi các roles)
- file inventory /etc/ansible/hosts (3)
- file trong roles/xxx/default (4)

group_vars và host_vars (Thư mục)

Thứ tự các file sắp xếp như dưới đấy. Việc oder file nào trước nằm ở mục Variable Priority

[tuanda@master-node nfs-server-client]$ cat inventory.yml 
[nfs_server]
pc1 ansible_ssh_host=192.168.56.12
[nfs_client]
pc2 ansible_ssh_host=192.168.56.13

[tuanda@master-node nfs-server-client]$ tree
.
├── group_vars
│   ├── all.yml
│   ├── nfs_client
│   │   ├── nfs_client.yml
│   │   └── nfs_server.yml
│   └── nfs_server
├── host_vars
│   ├── pc1.yml
│   └── pc2.yml
├── inventory.yml
├── nfs.yml
└── roles

Copy

- name: Upload package require
  copy:
    src: "{{ item }}.rpm"
    dest: /setup/
  loop: "{{ package_names }}"

Local Copy

Lưu file từ stdout > Ansible master

- name: "Storing Token"
  local_action: copy content={{ x.stdout }} dest=/tmp/token

Template


Unarchive

- name: Extract foo.tgz into /var/lib/foo
  unarchive:
    src: /var/lib/foo.tgz
    dest: /var/lib/foo/

Lookup get file

- name: Set authorized key took from file
  authorized_key:
    user: charlie
    state: present
    key: "{{ lookup('file', '/home/charlie/.ssh/id_rsa.pub') }}"

Loop

Ngoài loop theo item liệt kê. ta còn có thể loop theo variable theo loop.

loop:
  - {{ list_port }}

Verify inventory

Để kiểm tra Ansible đang load variable từ những file nào, giá trị latest ra sao, ta có thể chạy

ansible-inventory -i host.yaml --list    (dạng json)ansible-inventory -i host.yaml --list -y (dạng yaml)

Handler:

- name: "restart redis 1"
  service:
    name: "{{ redis_service_name }}"
    state: restarted
 Sau đó gọi bằng notify: restart redis 1

Create user if not exist

- name: check if redis user exists (ignore errors)
  command: id {{ redis_user }}
  ignore_errors: yes
  changed_when: false
  register: user_exists

- name: add redis group
  group:
    name: "{{ redis_group }}"
    state: present
  when: user_exists is failed

- name: add redis user
  user:
    name: "{{ redis_user }}"
    group: "{{ redis_group }}"
    comment: "Redis"
    home: "{{ redis_install_dir }}"
    shell: /bin/false
    system: yes
  when: user_exists is failed

when

VD1: Compare variable string

[redis_server] < Ta đặt inventory variable như sau:
192.168.122.129 install_redis=yes  redis_role=master
... 
when:
    - redis_role  == 'master'

Ví dụ 2: When with variable bool

Ta đặt default var là redis_tarball: false
  when: not redis_tarball
  when: redis_tarball
Nếu là false thì
nếu là string hoặc interger thì: 

For jinja

Link kiểm tra Jinja https://cryptic-cliffs-32040.herokuapp.com/ File default:

redis_save:
  - 900 1
  - 300 10
  - 60 10000

File template

{% for save in redis_save -%}
save {{ save }}
{% endfor -%}

IF ijnja

Trong file default mặc định để false. Nếu thay đổi thì xóa false đi và thay bằng string

redis_bind: false

Trong file Template

{% if redis_bind -%}
bind {{ redis_bind }}
{% else %}
bind 127.0.0.1
{% endif -%}
>>>> Hoặc, để bỏ dòng bind nếu false <<<<<
{% if redis_bind -%}
bind {{ redis_bind }}
{% endif -%}

Giải thích: Nếu false thì sẽ không có trong file config, nếu không false thì sẽ là string và kết quả là: requirepass matkhau

Ansible Vault

Phần 1: Tạo và chạy Vault (mã hóa all)

ansible-vault create test1.yaml
---
- hosts: api
  become: true
        
  tasks:
    - name: echo text
      shell: echo XINCHAO

ansible-vault edit test1.yaml
ansible-vault view test1.yaml
ansible-playbook test1.yaml --ask-vault-pass

Phần 2: Chèn vault vào variable

ansible-vault encrypt_string --vault-id @prompt thisismysupersecretstring
---
- hosts: api
  become: true

  vars:
    secret: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66666435303938323065643534376535633535353766323062633566313038313839343038336237
          3966616433326432643365623136383332313733646333390a333762663236393636613232663762
          33313861656264313061363265653031366538373662336132626465613839313335613862343464
          6436303837643761630a666532623532616431303632613466646661326566326332306264323236
          61383331333833333530373934356333653962396661336336653034306339306333        
  tasks:
    - name: echo text
      shell: echo {{ secret }}

Sau đó ta chạy
ansible-playbook test1_encrypt.yaml --ask-vauld-pass
ansible-playbook test1_encrypt.yaml --vault-password-file=pass.txt

Debug exec pod with no any command support

  Một ngày đẹp trời pod bị lỗi. Bạn thử ngay lệnh "kubectl exec -it ..." vào pod kiểm tra. Nhưng quãi đạn, pod không hỗ trợ bất kỳ...