如何在Docker中使用带密码的OpenGPG

392 阅读4分钟

如果你不想在你的设备上安装GPG/PGP来使用其命令,你可以尝试下面的Docker设置。通过目前的设置,你可以对信息进行加密和解密。唯一可以添加的是,文件加密和解密应该很容易。

无论你是发送方还是接收方,你都会被提示输入你的密码,用于make 命令。每个用户(测试)的个人资料都在.env.dist ,使用示例值。对于真正的用户,这个文件必须被复制为.env ,并包含真实的值。这个文件被排除在VCS提交以及/users/ 文件夹之外!

结构

这是原始状态:

├── .dockerignore
├── .env.dist
├── .gitignore
├── Dockerfile
├── Makefile
├── Readme.md
├── docker-compose.yaml
├── gpg.cfg
├── gpg.sh
└── users
    ├── ali
    │   └── msg-to-encrypt.txt
    └── bob
        └── msg-to-encrypt.txt

这是使用ali/bob作为发送方/接收方并运行以下命令后得到的结果:

├── .dockerignore
├── .env.dist
├── .gitignore
├── Dockerfile
├── Makefile
├── Readme.md
├── docker-compose.yaml
├── gpg.cfg
├── gpg.sh
└── users
    ├── ali
    │   ├── decrypted-msg.txt
    │   ├── encrypted-msg.txt
    │   ├── msg-to-decrypt.txt
    │   ├── msg-to-encrypt.txt
    │   ├── private.key
    │   ├── public.key
    │   └── trust.db
    └── bob
        ├── decrypted-msg.txt
        ├── encrypted-msg.txt
        ├── msg-to-decrypt.txt
        ├── msg-to-encrypt.txt
        ├── private.key
        ├── public.key
        └── trust.db

文件

ali/msg-to-encrypt.txt

Hello from Ali!

bob/msg-to-encrypt.txt

Hello from Bob!

.dockerignore

*
!/gpg.sh
!/gpg.cfg

.env.dist

ALI_NAME_REAL=Ali
ALI_NAME_COMMENT=Ali's account
ALI_NAME_EMAIL=ali@example.com
ALI_PASSPHASE=ali

BOB_NAME_REAL=Bob
BOB_NAME_COMMENT=Bob's account
BOB_NAME_EMAIL=bob@example.com
BOB_PASSPHASE=bob

.gitignore

users/*
!users/*/msg-to-encrypt.txt
.env

docker-compose.yaml

services:
  gpg:
    container_name: gpg
    build:
      context: "."
    env_file:
      - ".env"
    environment:
      - ACTION=${ACTION}
      - USER=${USER}
      - SENDER=${SENDER}
      - RECEIVER=${RECEIVER}
    volumes:
      - "./users:/users"

Dockerfile

FROM alpine:3.16.0
COPY . .
RUN apk update && apk fetch gnupg && apk add gnupg && chmod +x gpg.sh
ENTRYPOINT ["./gpg.sh"]

gig.cfg

Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: ${NAME_REAL}
Name-Comment: ${NAME_COMMENT}
Name-Email: ${NAME_EMAIL}
Expire-Date: 0
Passphrase: ${PASSPHASE}

gpg.sh

#!/bin/sh

set -eu

CYAN="\033[0;36m"
CLEAR="\033[0m"
GPG_DIR="/root/.gnupg"
USERS_DIR="/users"
PUBLIC_KEY_NAME="public.key"
PRIVATE_KEY_NAME="private.key"
TRUST_DB_NAME="trust.db"
DECRYPTED_MSG_NAME="decrypted-msg.txt"
ENCRYPTED_MSG_NAME="encrypted-msg.txt"
MESSAGE_TO_DECRYPT_NAME="msg-to-decrypt.txt"
MESSAGE_TO_ENCRYPT_NAME="msg-to-encrypt.txt"

gen_key() {
    printf "${CYAN}> GENERATE USER's PUBLIC and PRIVATE KEYS (begin) ----------------------------------------${CLEAR}\n"
    
    printf "${CYAN}Set local variables${CLEAR}\n"
    USER_NAME_REAL="$(echo ${USER} | tr 'a-z' 'A-Z')_NAME_REAL"
    USER_NAME_COMMENT="$(echo ${USER} | tr 'a-z' 'A-Z')_NAME_COMMENT"
    USER_NAME_EMAIL="$(echo ${USER} | tr 'a-z' 'A-Z')_NAME_EMAIL"
    USER_PASSPHASE="$(echo ${USER} | tr 'a-z' 'A-Z')_PASSPHASE"
    USER_PUB_KEY="${USERS_DIR}/${USER}/${PUBLIC_KEY_NAME}"
    USER_PRV_KEY="${USERS_DIR}/${USER}/${PRIVATE_KEY_NAME}"
    USER_TRUST_DB="${USERS_DIR}/${USER}/${TRUST_DB_NAME}"
    CONFIG_KEY="/gpg.cfg"
    echo "done"

    printf "${CYAN}Prepare configuration file${CLEAR}\n"
    sed -i \
        -e 's/${NAME_REAL}/'"$(printenv -- ${USER_NAME_REAL})"'/g' \
        -e 's/${NAME_COMMENT}/'"$(printenv -- ${USER_NAME_COMMENT})"'/g' \
        -e 's/${NAME_EMAIL}/'"$(printenv -- ${USER_NAME_EMAIL})"'/g' \
        -e 's/${PASSPHASE}/'"$(printenv -- ${USER_PASSPHASE})"'/g' \
        ${CONFIG_KEY}
    echo "done"

    printf "${CYAN}Create gpg directory and get into it${CLEAR}\n"
    gpg2 --list-keys
    cd ${GPG_DIR}

    printf "${CYAN}Generate keys${CLEAR}\n"
    gpg2 --verbose --batch --gen-key ${CONFIG_KEY}

    printf "${CYAN}Backup public and private keys${CLEAR}\n"
    gpg2 --yes --output ${USER_PUB_KEY} --armor --export-options export-backup --export $(printenv -- ${USER_NAME_EMAIL})
    gpg2 --yes --output ${USER_PRV_KEY} --armor --export-options export-backup --export-secret-keys $(printenv -- ${USER_NAME_EMAIL})
    echo "done"

    printf "${CYAN}Backup trust database${CLEAR}\n"
    gpg2 --export-ownertrust > ${USER_TRUST_DB}
    echo "done"

    printf "${CYAN}Cleanup${CLEAR}\n"
    cleanup
    echo "done"

    printf "${CYAN}> GENERATE USER's PUBLIC and PRIVATE KEYS (end) ------------------------------------------${CLEAR}\n"
}

enc_msg() {
    printf "${CYAN}> SENDER ENCRYPTS a PLAIN MESSAGE for RECEIVER to DECRYPT (begin) ------------------------${CLEAR}\n"

    printf "${CYAN}Set local variables${CLEAR}\n"
    SENDER_PUB_KEY="${USERS_DIR}/${SENDER}/${PUBLIC_KEY_NAME}"
    SENDER_PRV_KEY="${USERS_DIR}/${SENDER}/${PRIVATE_KEY_NAME}"
    SENDER_TRUST_DB="${USERS_DIR}/${SENDER}/${TRUST_DB_NAME}"
    SENDER_MSG_TO_ENCRYPT="${USERS_DIR}/${SENDER}/${MESSAGE_TO_ENCRYPT_NAME}"
    SENDER_ENCRYPTED_MSG="${USERS_DIR}/${SENDER}/${ENCRYPTED_MSG_NAME}"
    RECEIVER_PUB_KEY="${USERS_DIR}/${RECEIVER}/${PUBLIC_KEY_NAME}"
    RECEIVER_EMAIL="$(echo ${RECEIVER} | tr 'a-z' 'A-Z')_NAME_EMAIL"
    echo "done"

    printf "${CYAN}Create gpg directory and get into it${CLEAR}\n"
    gpg2 --list-keys
    cd ${GPG_DIR}

    printf "${CYAN}Restore sender's public key${CLEAR}\n"
    gpg2 --import-options import-restore --import ${SENDER_PUB_KEY}
    
    printf "${CYAN}Restore sender's private key${CLEAR}\n"
    gpg2 --import-options import-restore --import ${SENDER_PRV_KEY}

    printf "${CYAN}Restore sender's trust database${CLEAR}\n"
    rm trustdb.gpg
    gpg2 --import-ownertrust < ${SENDER_TRUST_DB}

    printf "${CYAN}Restore receiver's public key${CLEAR}\n"
    gpg2 --import-options import-restore --import ${RECEIVER_PUB_KEY}

    printf "${CYAN}Verify receiver's public key${CLEAR}\n"
    gpg2 --fingerprint $(printenv -- ${RECEIVER_EMAIL})

    printf "${CYAN}Sign receiver's public key${CLEAR}\n"
    gpg2 --sign-key $(printenv -- ${RECEIVER_EMAIL})

    printf "${CYAN}Sender encrypts message for receiver${CLEAR}\n"
    gpg2 --batch --yes --output ${SENDER_ENCRYPTED_MSG} --encrypt --sign --armor -r $(printenv -- ${RECEIVER_EMAIL}) ${SENDER_MSG_TO_ENCRYPT}
    echo "done"

    printf "${CYAN}Cleanup${CLEAR}\n"
    cleanup
    echo "done"
    
    printf "${CYAN}> SENDER ENCRYPTS a PLAIN MESSAGE for RECEIVER to DECRYPT (end) --------------------------${CLEAR}\n"
}

dec_msg() {
    printf "${CYAN}> RECEIVER DECRYPTS SENDER's ENCRYPTED MESSAGE (begin) -----------------------------------${CLEAR}\n"

    printf "${CYAN}Set local variables${CLEAR}\n"
    RECEIVER_PUB_KEY="${USERS_DIR}/${RECEIVER}/${PUBLIC_KEY_NAME}"
    RECEIVER_PRV_KEY="${USERS_DIR}/${RECEIVER}/${PRIVATE_KEY_NAME}"
    RECEIVER_TRUST_DB="${USERS_DIR}/${RECEIVER}/${TRUST_DB_NAME}"
    SENDER_PUB_KEY="${USERS_DIR}/${SENDER}/${PUBLIC_KEY_NAME}"
    SENDER_EMAIL="$(echo ${SENDER} | tr 'a-z' 'A-Z')_NAME_EMAIL"
    RECEIVER_MSG_TO_DECYPT="${USERS_DIR}/${RECEIVER}/${MESSAGE_TO_DECRYPT_NAME}"
    RECEIVER_DECRYPTED_MSG="${USERS_DIR}/${RECEIVER}/${DECRYPTED_MSG_NAME}"
    echo "done"

    printf "${CYAN}Create gpg directory and get into it${CLEAR}\n"
    gpg2 --list-keys
    cd ${GPG_DIR}

    printf "${CYAN}Restore receiver's public key${CLEAR}\n"
    gpg2 --import-options import-restore --import ${RECEIVER_PUB_KEY}
    
    printf "${CYAN}Restore receiver's private key${CLEAR}\n"
    gpg2 --import-options import-restore --import ${RECEIVER_PRV_KEY}

    printf "${CYAN}Restore receiver's trust database${CLEAR}\n"
    rm trustdb.gpg
    gpg2 --import-ownertrust < ${RECEIVER_TRUST_DB}

    printf "${CYAN}Restore sender's public key${CLEAR}\n"
    gpg2 --import-options import-restore --import ${SENDER_PUB_KEY}

    printf "${CYAN}Verify sender's public key${CLEAR}\n"
    gpg2 --fingerprint $(printenv -- ${SENDER_EMAIL})

    printf "${CYAN}Sign sender's public key${CLEAR}\n"
    gpg2 --sign-key $(printenv -- ${SENDER_EMAIL})

    printf "${CYAN}Receiver decrypts sender's encrypted message${CLEAR}\n"
    gpg2 --decrypt ${RECEIVER_MSG_TO_DECYPT} > ${RECEIVER_DECRYPTED_MSG}

    printf "${CYAN}Cleanup${CLEAR}\n"
    cleanup
    echo "done"

    printf "${CYAN}> RECEIVER DECRYPTS SENDER's ENCRYPTED MESSAGE (end) -------------------------------------${CLEAR}\n"
}

cleanup() {
    cd /
    rm -rf ${GPG_DIR}
    rm gpg.sh gpg.cfg
}

if [ ${ACTION} == "gen-key" ]; then gen_key; fi
if [ ${ACTION} == "enc-msg" ]; then enc_msg; fi
if [ ${ACTION} == "dec-msg" ]; then dec_msg; fi

制作文件

.PHONY: help
help: ## Display available commands.
	@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

.PHONY: gen-key
gen-key: ## Generate public and private keys for a user. Usage: `make gen-key USER=ali`
	make down
	ACTION=gen-key USER=${USER} docker-compose run --rm gpg

.PHONY: enc-msg
enc-msg: ## Sender encrypts plain message for receiver to decrypt. Usage: `make enc-msg SENDER=ali RECEIVER=bob`
	make down
	ACTION=enc-msg SENDER=${SENDER} RECEIVER=${RECEIVER} docker-compose run --rm gpg

.PHONY: dec-msg
dec-msg: ## Receiver decrypts sender's encrypted message. `make dec-msg SENDER=ali RECEIVER=bob`
	make down
	ACTION=dec-msg SENDER=${SENDER} RECEIVER=${RECEIVER} docker-compose run --rm gpg

.PHONY: config
config: ## Dump docker-compose configuration.
	docker-compose config

.PHONY: down
down: ## Clean up docker artefacts.
	docker-compose down
	@-docker rmi gpg_gpg
	docker system prune --volumes --force

命令

生成密钥

它创建公钥和私钥,然后将它们备份到/users/{name}/ 文件夹中,包括 "信任 "数据库。创建的文件是private.key,public.keytrust.db 。然后,public.key 可以与第三方共享,以解密信息:

$ make gen-key USER=Ali

> GENERATE USERs PUBLIC and PRIVATE KEYS (begin) ----------------------------------------
Set local variables
done
Prepare configuration file
done
Create gpg directory and get into it
gpg: directory /root/.gnupg created
gpg: keybox /root/.gnupg/pubring.kbx created
gpg: /root/.gnupg/trustdb.gpg: trustdb created
Generate keys
gpg: no running gpg-agent - starting /usr/bin/gpg-agent
gpg: waiting for the agent to come up ... (5s)
gpg: connection to agent established
gpg: writing self signature
gpg: RSA/SHA512 signature from: "C8338E605AB8E7E4 [?]"
gpg: writing key binding signature
gpg: RSA/SHA512 signature from: "C8338E605AB8E7E4 [?]"
gpg: RSA/SHA512 signature from: "04FD871034B69D9D [?]"
gpg: writing public key to /root/.gnupg/pubring.kbx
gpg: using pgp trust model
gpg: directory /root/.gnupg/openpgp-revocs.d created
gpg: writing to /root/.gnupg/openpgp-revocs.d/B653C89FC6B35C84A5B85CA7C8338E605AB8E7E4.rev
gpg: RSA/SHA512 signature from: "C8338E605AB8E7E4 Ali (Alis account) <ali@example.com>"
gpg: revocation certificate stored as /root/.gnupg/openpgp-revocs.d/B653C89FC6B35C84A5B85CA7C8338E605AB8E7E4.rev
Backup public and private keys
done
Backup trust database
done
Cleanup
done
> GENERATE USERs PUBLIC and PRIVATE KEYS (end) ------------------------------------------

加密密钥

它可以帮助发送者为接收者解密的明文信息进行加密。发送方的明文信息必须放到/users/{sender_name}/msg-to-encrypt.txt 文件中。成功的操作将把加密的信息放入/users/{sender_name}/encrypted-msg.txt 文件。这个文件可以与拥有你的公钥的接收者共享,以便解密:

$ make enc-msg SENDER=ali RECEIVER=bob

> SENDER ENCRYPTS a PLAIN MESSAGE for RECEIVER to DECRYPT (begin) ------------------------
Set local variables
done
Create gpg directory and get into it
gpg: directory /root/.gnupg created
gpg: keybox /root/.gnupg/pubring.kbx created
gpg: /root/.gnupg/trustdb.gpg: trustdb created
Restore senders public key
gpg: key C8338E605AB8E7E4: public key "Ali (Alis account) <ali@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
Restore senders private key
gpg: key C8338E605AB8E7E4: "Ali (Alis account) <ali@example.com>" not changed
gpg: key C8338E605AB8E7E4: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1
Restore senders trust database
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: inserting ownertrust of 6
Restore receivers public key
gpg: key 6BA9B4E9279E259C: public key "Bob (Bobs account) <bob@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
Verify receivers public key
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   rsa2048 2022-06-03 [SCEA]
      E464 CA1D C0A4 A8F5 D473  0160 6BA9 B4E9 279E 259C
uid           [ unknown] Bob (Bobs account) <bob@example.com>
sub   rsa2048 2022-06-03 [SEA]

Sign receivers public key

pub  rsa2048/6BA9B4E9279E259C
     created: 2022-06-03  expires: never       usage: SCEA
     trust: unknown       validity: unknown
sub  rsa2048/8C840512707375BB
     created: 2022-06-03  expires: never       usage: SEA
[ unknown] (1). Bob (Bobs account) <bob@example.com>


pub  rsa2048/6BA9B4E9279E259C
     created: 2022-06-03  expires: never       usage: SCEA
     trust: unknown       validity: unknown
 Primary key fingerprint: E464 CA1D C0A4 A8F5 D473  0160 6BA9 B4E9 279E 259C

     Bob (Bobs account) <bob@example.com>

Are you sure that you want to sign this key with your
key "Ali (Alis account) <ali@example.com>" (C8338E605AB8E7E4)

Really sign? (y/N) y

Sender encrypts message for receiver
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   1  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: depth: 1  valid:   1  signed:   0  trust: 1-, 0q, 0n, 0m, 0f, 0u
done
Cleanup
done
> SENDER ENCRYPTS a PLAIN MESSAGE for RECEIVER to DECRYPT (end) ---------------------

解密密钥

它帮助接收方解密发送方的加密信息。发送方的加密信息必须放到/users/{receiver_name}/msg-to-decrypt.txt 文件中。成功的操作将把解密的信息放入/users/{receiver_name}/decrypted-msg.txt 文件:

$ make dec-msg SENDER=ali RECEIVER=bob

> RECEIVER DECRYPTS SENDERs ENCRYPTED MESSAGE (begin) -----------------------------------
Set local variables
done
Create gpg directory and get into it
gpg: directory /root/.gnupg created
gpg: keybox /root/.gnupg/pubring.kbx created
gpg: /root/.gnupg/trustdb.gpg: trustdb created
Restore receivers public key
gpg: key 6BA9B4E9279E259C: public key "Bob (Bobs account) <bob@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
Restore receivers private key
gpg: key 6BA9B4E9279E259C: "Bob (Bobs account) <bob@example.com>" not changed
gpg: key 6BA9B4E9279E259C: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1
Restore receivers trust database
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: inserting ownertrust of 6
Restore senders public key
gpg: key C8338E605AB8E7E4: public key "Ali (Alis account) <ali@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
Verify senders public key
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   rsa2048 2022-06-03 [SCEA]
      B653 C89F C6B3 5C84 A5B8  5CA7 C833 8E60 5AB8 E7E4
uid           [ unknown] Ali (Alis account) <ali@example.com>
sub   rsa2048 2022-06-03 [SEA]

Sign senders public key

pub  rsa2048/C8338E605AB8E7E4
     created: 2022-06-03  expires: never       usage: SCEA
     trust: unknown       validity: unknown
sub  rsa2048/04FD871034B69D9D
     created: 2022-06-03  expires: never       usage: SEA
[ unknown] (1). Ali (Alis account) <ali@example.com>


pub  rsa2048/C8338E605AB8E7E4
     created: 2022-06-03  expires: never       usage: SCEA
     trust: unknown       validity: unknown
 Primary key fingerprint: B653 C89F C6B3 5C84 A5B8  5CA7 C833 8E60 5AB8 E7E4

     Ali (Alis account) <ali@example.com>

Are you sure that you want to sign this key with your
key "Bob (Bobs account) <bob@example.com>" (6BA9B4E9279E259C)

Really sign? (y/N) y

Receiver decrypts senders encrypted message
gpg: encrypted with 2048-bit RSA key, ID 8C840512707375BB, created 2022-06-03
      "Bob (Bobs account) <bob@example.com>"
gpg: Signature made Fri Jun  3 20:44:12 2022 UTC
gpg:                using RSA key 4B874F8387E97D9044FF8A4B04FD871034B69D9D
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   1  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: depth: 1  valid:   1  signed:   0  trust: 1-, 0q, 0n, 0m, 0f, 0u
gpg: Good signature from "Ali (Alis account) <ali@example.com>" [full]
Cleanup
done
> RECEIVER DECRYPTS SENDERs ENCRYPTED MESSAGE (end) -------------------------------------