捐血一袋救人一命

江蘇拙政園

江蘇 拙政園

全家福

日本 和歌山城

賞楓之旅

千燈 夕照

水鄉千燈

蘆洲 微風運河

破曉時分

2024年7月18日 星期四

以 Windows 內建的 AppLocker 來管制使用者執行/安裝應用程式

AppLocker 是一個用來管制電腦可以運行的程式、Installer(.msi)、指令碼(.bat, .cmd, .vbs, .ps1, .js,...)、DLL、封裝的應用程式(.app, .appx)的服務。 

它從 Windows Server 2008 R2/Windows 7 就已經存在,但是卻很少人使用它。

其實搞懂它之後,它就是免費強大的資安管理系統!

要使用 AppLocker,有一個必要條件,Windows 10 版本需要更新到 22H2 版本以後,不然即使設定好相關的政策與服務,AppLocker 也不會生效!

AppLocker 要依靠 AppIDSvc 服務(Application Identity),看名字就知道是用來識別應用程式的服務 。

但是,在Windows 10 的服務管理,卻無法設定該服務於開機時自動啟動! 
網路上多是叫你用 sc.exe 來設定該服務
sc config appidsvc start=auto
或是去修改機碼
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AppIDSvc] "Start"=dword:00000002
其實 AppIDSvc 是由 AppID 服務控制,只要設定 AppID 開機自動啟動,AppIDSvc 開機就會自動啟動(但是服務啟動類型仍顯示為手動啟動) 你可以使用
sc config appid start=auto
或是使用 Powershell
Set-Service -Name AppID -Startup Automatic


注意:這個 AppID 在服務裡是找不到的!所以你沒辦法用服務管理 GUI 來維護。(個人猜測,本來是要在 AD 環境管理的;但是我是沒有AD的環境,只能這樣處理)

當你重新開機,讓 AppID & AppIDSvc 服務啟動之後

你可以透過 c:\windows\system32\secpol.msc 啟動 本機安全性原則管理程式。

安全性原則 > 應用程式控制原則 > AppLocker

它分成四大類可以運行的程式

  1. 可執行檔規則
  2. Windows Installer 規則
  3. 指令碼規則
  4. 已封裝的應用程式規則

這四項當中,如果都沒有任何規則時,預設是全部允許執行!

但是,當你設定有任何一個規則,預設是全部不允許!所以你要做的就是設定哪些程式允許被執行!


要讓所有人可以正常運行Windows基本功能,請在這四大項,建立預設規則(D)

 

另外,當你要設定拒絕規則時,請不要使用內建的 Users 群組名稱,這會造成連管理者都被拒絕執行!請務必自行建立一個新群組名稱,然後把使用者帳號加入群組,然後設定該群組拒絕執行。


AppLocker

Powershell cmdlet for AppLocker

Docker Engine API

Docker Engine API

Docker 的架構

  • 下圖是 Docker 官方的架構圖
  • 由圖可知,Docker Client 與 Docker Host 是可以分開的
  • 而我們一般運行 Docker,Client & Host 是同一台伺服器
    image.png
  • Docker Engine 提供了 Web API,讓你可以使用慣用的程式語言來控制 Docker Engine,甚至 Docker Container Apps 的數量(Scale Up/Down)
  • 另外,Docker Engine 也提供了 SDK for Go & Python,熟悉這兩種語言的人,可以直接使用 SDK
  • Docker Engine API 是 RESTful API,你可以很輕鬆地使用 wget, curl, powershell, 或是你慣用的程式語言來存取它。
  • 要使用 Docker Engine API 之前,必須先知道你的 Docker Engine 版本所使用的 API 版本

查詢 Docker API 版本可以使用以下命令

docker version

image.png

啟用 Docker Engine API

Docker Engine API 預設是沒有啟動的,必須自行設定,設定步驟如下

  1. 開啟遠端 Docker Host 上的 Docker Service 設定檔
# 以 systemctl 讀取服務設定
# 第一行是設定檔路徑檔名
# 將第一行的註解符號去除掉,得到完整路徑檔名
# 存入環境變數
DOCKER_SERVICE_CONF_FILE=$(systemctl cat docker.service | head -n 1 | sed 's/^#\s//g')
vi ${DOCKER_SERVICE_CONF_FILE}

# vi /usr/lib/systemd/system/docker.service
  1. 修改其中 ExecStart 的命令,增加 -H tcp://0.0.0.0:2375 並存檔。
    image.png

  2. 然後讓 systemd 重新載入 Daemon 相關設定檔,然後重新啟動 Docker

# 讓 systemd 重新載入 Daemon 設定檔
sudo systemctl daemon-reload
# 重新啟動 Docker Daemon
sudo systemctl restart docker
# 檢查 Docker Service 狀態
sudo systemctl status docker

如果有正常啟動 docker daemon 會看到如下圖

image.png

  1. 檢查 Docker 是否有監聽 2375 Port
sudo lsof -i -P -n | grep dockerd

image.png

sudo ss -tulpn | grep dockerd

image.png

以上就完成了啟用 Docker Engine API


Docker Engine API v1.43 簡單列舉容器相關操作

查詢 Container 資訊

Method: GET
http://{docker_host_ip}:2375/containers/json

參數 說明
all boolean,預設值為 false/0,表示只回傳正在運行的容器資訊;all=true/1,表示回傳所有容器資訊;注意這裡數值的布林值,與Python相同,只有0代表 false,其他數值,不管正負,都代表true
limit integer,回傳最近幾個Container的資訊,包含沒有在運行的容器
size boolean,預設值為 false,回傳資訊增加容器大小
filters string,設定篩選容器的條件

可用的 filters

參數 說明
ancestor 指定 “ancestor”: [“image_name”:“image_tag”]
before 指定 container_id 或 container_name之前的容器
expose 指定 expose port
exited 指定 container exit code
health 指定狀態:starting, healthy, unhealthy, none
id 指定 Container ID
isolation 指定隔離狀態:default, process, hyperv;Windows Daemon Only
label 指定 {“label”:[“key”]} 或是 {“label”:[“key=value”]}
name 指定Container Name
network 指定 network_id 或 network_name
publish 指定 port/proto 或 startport-endport/proto
since 指定 container_id 或 container_name之後的容器
status 指定特定狀態的容器:created, restarting, running, removing, paused, exited, dead
volume 指定volume_name 或 volume_id

範例:

curl http://192.168.13.161:2375/containers/json?all=1
curl http://192.168.13.161:2375/v1.43/containers/json?filters={"ancestor": ["nginx:latest"]}
curl http://192.168.13.161:2375/containers/json?filters={"label":["CallFrom=Powershell"]}

查詢指定的 Container 資訊

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/json

查看 Container 內部運行的程式

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/top

查看 Container 運行的 Log

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/logs

查看 Container 內部被異動的檔案/目錄

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/changes

匯出 Container 並下載

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/export

持續回傳容器運行資源狀態(JSON)

Method: GET

http://{docker_host_ip}:2375/containers/[container_id | container_name]/stats

建立容器(注意:容器只有建立,並沒有運行)

Method: POST

http://{docker_host_ip}:2375/container/create
網址參數 說明
name string,必須符合正規式 ^/?[a-zA-Z0-9][a-zA-Z0-9_.-]+$

Header請指定 “Content-Type: application/json”

Body JSON 簡單列舉參數如下

參數名稱 說明
Env Array of Strings,指定環境變數及值
Cmd Array of Strings,指定容器啟動時,要執行的命令
Image string,指定容器要使用的 Image Name 以及 Tag
Volumes 指定掛載的磁碟
WorkingDir 指定命令要在哪個目錄下運行
Labels 指定 Key/Value 的 Metadata
HostConfig 設定網路相關資訊,例如:Port Mapping

範例:

使用 bash shell curl 建立 Container

curl -X POST -H "Content-Type: application/json" \
-d '{"Image": "nginx:latest", "ExposedPorts": { "80/tcp": {} }, "HostConfig": { "PortBindings": { "80/tcp": [{ "HostIp": "", "HostPort": "9001" }] } } }' \
http://192.168.213.214:2375/containers/create

使用 Powershell 跑迴圈,建立三個 Container:web01, web02, web03,分別使用 Port 9001, 9002, 9003,並啟動這三個Container

$head = @{ 'Content-Type' = 'application/json' }

$Port = 9000
For($i=1; $i -le 3; $i++){
    $Port++
    $json  = "{""Image"": ""nginx:latest"", "
    $json += """ExposedPorts"": { ""80/tcp"": {} }, "
    $json += """HostConfig"": { ""PortBindings"": { ""80/tcp"": [{ ""HostIp"": ""0.0.0.0"", ""HostPort"": ""$Port"" }] } }, "
    $json += """Labels"" : {""CallFrom"":""Powershell""} }"

    # Create Container
    Invoke-RestMethod -Method POST -Uri ("http://192.168.13.161:2375/containers/create?name=web{0:d2}" -f $i) -Headers $head -Body $json
    # Start Container
    Invoke-RestMethod -Method POST -Uri ("http://192.168.13.161:2375/containers/web{0:d2}/start" -f $i) -Headers $head
}

啟動執行容器(Start)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/start

停止運行容器(Stop)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/stop

重新啟動執行容器(Restart)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/restart

傳送 POSIX signal 給容器(Kill)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/kill?signal=[SIGNAL_STRING | SIGNAL_CODE]

變更容器名稱(Rename)

Method: POST

http://{docker_host_ip}:2375/containers/[container_id | container_name]/rename?name=[new_container_name]

刪除容器名稱(Remove)

Method: DELETE

http://{docker_host_ip}:2375/containers/[container_id | container_name]

以上,當你使用錯誤的 Method 時,會顯示 page not found 錯誤訊息

image.png

參考資料

Configure remote access for Docker daemon
Docker Engine API (1.43)
Docker Engine API version history
Develop with Docker Engine SDKs

docker config

docker config

  • 這個命令是用在 Docker Swarm 環境下
  • 你可以將你的應用程式容器需要的靜態檔案/設定檔,透過 docker config create 存到 Manager Node 上。
  • 當你的應用程式容器在 Worker Nodes 上部署運行時,可以將這些 config 檔案掛載到容器之中
  • 它跟 Volume 的差異,在於 Volume 的掛載是無法跨 Nodes,除非每個 Nodes 都去掛載網路磁碟(smb/nfs/…)

指令表

指令 Description 說明
docker config create Create a config from a file or STDIN 從 STDIN 或是應用程式設定檔來建立 config
docker config inspect Display detailed information on one or more configs 顯示 config 的詳細資訊(其中包含檔案被base64編碼的內容)
docker config ls List configs 條列 Manager Node 上的 config
docker config rm Remove one or more configs 刪除指定的 config

用實例離說明:

部署簡單的 php 程式到 Worker Node web

  1. 建立簡單的 php 程式檔案作為首頁 index.php,用來驗證部署結果
<?php
// 獲取伺服器的 IP 地址
$server_ip = $_SERVER['SERVER_ADDR'];

// 顯示在網頁上
echo "伺服器的 IP 地址是: " . $server_ip;

phpinfo()
?>
  1. 建立 apache 虛擬主機設定檔 ~/000-default.conf
<VirtualHost *:80>
    ServerAdmin webmaster@official.company.com
    ServerName official.company.com
    DocumentRoot /var/www/html

    <Directory /var/www/html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
  1. 以 apache 虛擬主機設定檔 000-default.conf,在 Docker Swarm Manager Node 上,建立 config
docker config create apache_vhost ./000-default.conf
  1. 列出 config,確認一下
docker config ls

image

  1. 檢查一下 apache vhost config 詳細資訊,你會發現,設定檔內容以 base64 編碼,存在 Data 中
docker config inspect apache_vhost

image

  1. 驗證一下apache_vhost config內容
docker config inspect apache_vhost | jq -r '.[0].Spec.Data' | base64 --decode

image

  1. 驗證一下 index.php config內容
docker config inspect official_homepage | jq -r '.[0].Spec.Data' | base64 --decode

image

  1. 編寫 docker-compose.yml
version: '3.8'

services:
  php_apache:
    image: php:7.1-apache
    deploy:
      replicas: 1
      placement:
        constraints: [node.labels.server == web]
    configs:
      - source: official_homepage
        target: /var/www/html/index.php
        uid: '33'
        gid: '33'
        mode: 0444
      - source: apache_vhost
        target: /etc/apache2/sites-available/000-default.conf
    networks:
      - my_network

configs:
  official_homepage:
    external: true
  apache_vhost:
    external: true

networks:
  my_network:
    driver: overlay
  1. 執行 odcker stack deploy 進行部署
docker stack deploy -c docker-compose.yml official_homepage

image
10. 檢查一下,看看 config 是不是都被容器掛載到對應的路徑

docker ps -a
docker exec -it 6476ac33e359 cat /var/www/html/index.php
docker exec -it 6476ac33e359 cat /etc/apache2/sites-available/000-default.conf

image

  • 從上圖可以看到, php:7.1-apache 被部署到 server 標籤為 web 的 node (lab2)
  • index.php 與 000-default.conf 也都被掛載到正確的路徑下了

2024年7月1日 星期一

Linux 上常用的打包壓縮軟體

Linux 上常見的打包、壓縮軟體

  • tar:(Tape Archive)是一個用於檔案打包的工具,最早用於將多個檔案和目錄打包成一個檔案,便於在磁帶等存儲設備上進行備份和傳輸。
  • gzip:使用 DEFLATE 算法,基於 LZ77 和霍夫曼編碼。
  • bzip2:使用 Burrows-Wheeler 變換和 Run-Length Encoding (RLE) 算法,並結合霍夫曼編碼。
  • xz:使用 LZMA(Lempel-Ziv-Markov chain algorithm)算法,這是一種高度優化的壓縮算法,提供了非常高的壓縮比。

要注意的是,tar 只是打包工具,將多個檔案目錄屬性擁有者ID 等資訊打包成一個 tarball File,本身並沒有壓縮

所以使用 tar,會搭配 gzip, bzip2, 或是 xz 等壓縮工具,來節省空間或是傳書時間

壓縮比:gzip < bzip2 < xz
壓縮速度:gzip > bzip2 > xz
解壓縮速度:gzip > bzip2 > xz
資源用量:gzip < bzip2 < xz

雖然 7z & rar 都有 for Linux 版本,不過在 Linux 上並不流行

tar 搭配 gzip 打包壓縮

tar -zcvf archive.tar.gz /path/to/directory ...

有的人會將 archive.tar.gz 直接命名為 archive.tgz

tar 搭配 bzip2 打包壓縮

tar -jcvf archive.tar.bz2 /path/to/directory ...

注意:參數 j 是小寫

tar 搭配 xz 打包壓縮

tar -Jcvf archive.tar.xz /path/to/directory ...

注意:參數 J 是大寫


常用參數意義

參數 說明
c Create archive
v Verbosely
f use archive file or device ARCHIVE
t List all files in archive
x Extract files from archive
A append tar files to an archive
d find differences between archive and file system
r append files to the end of an archive
u only append files newer than copy in archive

接下來,搭配 ssh,進行遠端管理

命令遠端伺服器壓縮資料

ssh user@box tar zcvf - /dir1/ > /destination/file.tar.gz

將 tar 打包輸出的結果,透過 Pipe 傳給 gzip,並指定 gzip 壓縮程度

ssh user@box 'cd /dir1/ && tar -cf - file | gzip -9' >file.tar.gz

壓縮本機檔案,然後透過 SSH 傳送到遠端伺服器保存

tar zcvf - /wwwdata | gzip | ssh user@dumpserver.nixcraft.in "cat > /backup/wwwdata.tar.gz"

tar 打包壓縮 > gpg加密 > ssh 傳送到遠端主機 cat 輸出成檔案

tar zcf - /data2/ | gpg -e | ssh vivek@nas03 'cat - > data2-dd-mm-yyyy.tar.gz.gpg'

如果遠端伺服器需要特權,ssh 加上 -t 參數,使用 sudo

tar zcvf - /wwwdata | ssh -t vivek@192.168.1.201 "sudo cat > /backup/wwwdata.tar.gz"

命令遠端伺服器壓縮檔案,並傳送到本機目前路徑

cd /path/local/dir/ && ssh vivek@server1.cyberciti.biz 'tar zcf - /some/dir' | tar zxf -

使用 dd 指令備份硬碟 /dev/sdvf 到遠端

dd if=/dev/sdvf | ssh backupimg@vpc-aws-mumbai-backup-001 'dd of=prod-disk-hostname-sdvf-dd-mm-yyyy.img'

從遠端備份硬碟資料還原到本地端

ssh backupimg@vpc-aws-mumbai-backup-001 'dd if=prod-disk-hostname-sdvf-dd-mm-yyyy.img' | dd of=/dev/sdvf

使用 SCP 備份,遇到連結或是特殊裝置路徑就會失敗,可以使用 tar 來備份

ssh vivek@nuc-box 'tar czf - /home/vivek' | tar xvzf - -C /home/vivek
cat my-data.tar.gz | ssh user@server1.cyberciti.biz "cd /path/to/dest/; tar zxvf -"

顯示壓縮進度條

cd /dir/to/backup/ && tar zcf - . | pv | ssh vivek@server1.cyberciti.biz "cat > /backups/box42/backup-dd-mm-yyyy.tgz"