跳至主要内容

ocserv + Let's Encrypt + 证书登录

参考链接:
http://blog.dazzyd.org/blog/ocserv-letsencrypt-certificate/
https://nova.moe/deploy-openconnect-ocserv-with-letsencrypt/
https://ipbgp.com/2017/08/29/cisco-anyconnect/

简要原理

以下包含口胡,欢迎指正。

TLS/SSL 证书认证

TLS/SSL 协议的允许连接双方都对端做身份认证。
对服务器端认证一般采用证书认证的,对客户端认证一般采用用户名+密码的认证。
由于每次都输入密码较为繁琐,因此对客户端亦采用证书认证的方式能更方便。

Let’s Encrypt 签发流程 (WebRoot)

  1. 客户端生成验证文件,存放到 WEBROOT/.well-known/acme-challenge/
  2. 客户端告知 Let’s Encrypt 服务器开始验证
  3. 服务器读取 http://DOMAIN/.well-known/acme-challenge/ 进行验证
  4. 客户端向服务器查询验证是否成功
  5. 若验证成功,向服务器获取证书
其中 1、3 为可能出现问题的地方,若获取证书失败,建议优先检查此部分。
如:WEBROOT 不可被 letsencrypt 客户端写入;Let’s Encrypt 服务器无法解析 DOMAIN 的 DNS;DOMAIN 对应的 IP 非 Let’s Encrypt 客户端写入验证文件的主机等诸多问题。
转注:apache的ssl服务会默认占用443端口,可以在/etc/httpd/conf.d/ssl.conf中进行修改,避免与ocserv端口相同。

服务器证书

自建 CA 并签发服务器证书固然是可行方案,但需要在每台设备上都信任该自建 CA,较为麻烦且不安全。
因此我采用 Let’s Encrypt 来获取合法的服务器证书。
以下大部分命令需要 root 权限,但可以通过配置目录的读写权限绕过。
建议同时阅读 Let’s Encrypt User Guide

事前准备

  1. 将域名 DOMAIN 的 A/AAAA 记录指向当前主机。
  2. 配置 HTTP 服务器,使 WEBROOT/.well-known/acme-challenge/ 可被访问。

获取证书

测试时建议加上 --test-cert 以免用完 Let’s Encrypt 的证书获取速率限制。
避免在申请或更新证书时需要停止httpd服务,使用webroot方式获取证书。

yum install certbot
certbot certonly --webroot -w WEBROOT -d DOMAIN

自动更新证书

添加 cron 脚本至 /etc/cron.monthly/certbot,实现每月自动更新。

#!/bin/bash

WD="/root/certbot"
LOG="${WD}/cron.log"

mkdir -p $WD
date >> $LOG
certbot renew >> $LOG

用户证书

用户证书只需 ocserv 信任 CA 即可,因此使用自建 CA 签发证书。
将以下脚本保存到 /etc/ocserv/certs/,然后运行 ./ocm generate USERNAME 即可直接生成用户证书 USERNAME.p12

#!/bin/bash

init() {
    WORK="./work"
    CA_TMPL="${WORK}/ca.tmpl"
    CA_KEY="${WORK}/ca-key.pem"
    CA_CERT="./ca.pem"
    USER="$1"
    USER_TMPL="${WORK}/${USER}.tmpl"
    USER_KEY="${WORK}/${USER}-key.pem"
    USER_CERT="${WORK}/${USER}.pem"
    USER_P12="./${USER}.p12"
    REVOKED_CERT="${WORK}/revoked.pem"
    CRL_TMPL="${WORK}/crl.tmpl"
    CRL_CERT="./crl.pem"

    # Ensure working directory
    [[ -d $WORK ]] || mkdir -p $WORK

    # CA Template
    [[ -f $CA_TMPL ]] || cat << _EOF_ > $CA_TMPL
cn = "VPN CA"
serial = 1
expiration_days = 3650
ca
signing_key
cert_signing_key
crl_signing_key
_EOF_

    # CA Private Key
    [[ -f $CA_KEY ]] || certtool --generate-privkey --outfile $CA_KEY

    # CA Certificate
    [[ -f $CA_CERT ]] || certtool --generate-self-signed --load-privkey $CA_KEY --template $CA_TMPL --outfile $CA_CERT
}

generate() {
    # User Template
    cat << _EOF_ > $USER_TMPL
cn = "$USER"
expiration_days = 3650
signing_key
tls_www_client
_EOF_

    # User Private Key
    certtool --generate-privkey --outfile $USER_KEY

    # User Certificate
    certtool --generate-certificate --load-privkey $USER_KEY --load-ca-certificate $CA_CERT --load-ca-privkey $CA_KEY --template $USER_TMPL --outfile $USER_CERT

    # Export User Certificate
    certtool --to-p12 --pkcs-cipher 3des-pkcs12 --load-privkey $USER_KEY --load-certificate $USER_CERT --outfile $USER_P12 --outder
}

revoke() {
    # Copy User Certificate to Revoked Certificate
    cat $USER_CERT >> $REVOKED_CERT

    # CRL Template
    [[ -f $CRL_TMPL ]] || cat << _EOF_ > $CRL_TMPL
crl_next_update = 3650
crl_number = 1
_EOF_

    # CRL Certificate
    certtool --generate-crl --load-certificate $REVOKED_CERT --load-ca-privkey $CA_KEY --load-ca-certificate $CA_CERT --template $CRL_TMPL --outfile $CRL_CERT
}

case $1 in
    generate)
        init $2
        generate
        ;;
    revoke)
        init $2
        revoke
        ;;
    *)
        echo "\
Usage:
    $0 generate USER
    $0 revoke USER
"
esac

ocserv

编译安装 ocserv

注意安装依赖,阅读 README.md 即可。

VERSION='0.10.11'
cd /opt
wget ftp://ftp.infradead.org/pub/ocserv/ocserv-${VERSION}.tar.xz
tar xvf ocserv-${VERSION}.tar.xz
cd ocserv-${VERSION}
./configure
make
make install

配置 ocserv

复制配置文件:cp /opt/ocserv-${VERSION}/doc/sample.config /etc/ocserv/ocserv.conf
修改以下项:

# 打开 PMTUD
try-mtu-discovery = true

# 以 CN 为用户 ID。(用户证书认证)
cert-user-oid = 2.5.4.3

# 服务器证书与密钥(Let's Encrypt)
server-cert = /etc/letsencrypt/live/DOMAIN/fullchain.pem
server-key = /etc/letsencrypt/live/DOMAIN/privkey.pem

# 如有需要,可修改 VPN 端口
tcp-port = 443
udp-port = 443

# 修改 VPN 子网网段(避免和常用内网网段相同)
ipv4-network = 192.168.111/24

# 修改 DNS
dns = 8.8.8.8
dns = 8.8.4.4

# 注释掉所有的 route,让服务器成为 gateway
#route = 192.168.1.0/255.255.255.0

配置服务器

修改 /etc/sysctl.conf 中的 net.ipv4.ip_forward=1,然后刷新配置 sysctl -p /etc/sysctl.conf
修改 iptables,注意对 iptables 做持久化。

# 若强化了服务器安全,需要开放 443 端口。
iptables -A INPUT -p tcp -m state --state NEW --dport 443 -j ACCEPT
iptables -A INPUT -p udp -m state --state NEW --dport 443 -j ACCEPT
iptables -D FORWARD -j DROP

# 打开 NAT
iptables -t nat -A POSTROUTING -j MASQUERADE

测试 ocserv

修改 ocserv.conf 中的 auth = "plain[passwd=/etc/ocserv/passwd]"
创建用户 ocpasswd -c /etc/ocserv/passwd your-username
运行 ocserv ocserv -f -d 1,在手机上尝试连接。

配置证书认证

修改 /etc/ocserv/ocserv.conf 中的以下项:

auth = "certificate"
ca-cert = /etc/ocserv/certs/ca-cert.pem
#第二种方式:指定替代的登录方式,这里使用证书登录作为第二种登录方式
enable-auth = "certificate"

重新运行、测试连接。

附录

以 service 运行 ocserv (Ubuntu)

执行以下指令

ln -s /lib/init/upstart-job /etc/init.d/ocserv

cat << _EOF_ > /etc/init/ocserv.conf
#!upstart
description "OpenConnect Server"

start on runlevel [2345]
stop on runlevel [06]

respawn
respawn limit 20 5

script
    exec start-stop-daemon --start --pidfile /var/run/ocserv.pid --exec /usr/local/sbin/ocserv -- -f >> /dev/null 2>&1
end script
_EOF_

启动服务:service ocserv start
停止服务:service ocserv stop

安装用户证书

iOS, Android

  1. 将生成的用户证书 USER.p12 复制到 WEBROOT
  2. 打开 AnyConnect 客户端,切换到 Diagnostics 页。
  3. 点击 Certificates 项,点击 Import User Certiticate…
  4. 输入 http://DOMAIN/USER.p12,然后输入密码。
  5. 在连接设置的证书一项,选择刚刚导入的证书(可选)。

macOS

1. 将p12文件下载到本地,双击安装。
2. 在钥匙串中设置为始终信任。

评论

  1. 博主大大,有关“用户证书只需 ocserv 信任 CA 即可,因此使用自建 CA 签发证书。将以下脚本保存到 /etc/ocserv/certs/,然后运行 ./ocm generate USERNAME 即可直接生成用户证书 USERNAME.p12”这段话 我不是很明白(本人小白,最近在折腾OpenWrt上的ocserv和证书),我在OpenWrt上通过acme.sh申请到了Let's Encrypt的免费证书(ca-cert.pem , server-key.pem 和 server-cert.pem)并将这三个文件安装到/etc/ocserv/ssl/的目录,您说的“使用自建 CA 签发证书”是要自己建立ca模板并重新生成自建的ca-key和ca-cert以及server-key和server-cert最终再生成User-key和user-cert,合成P12证书吗?

    回复删除

发表评论

此博客中的热门博文

Resolving errSecInternalComponent errors during code signing

原文链接 One code signing issue I commonly see, both here on DevForums and in my Day Job™ with DTS, is that the codesign command fails with errSecInternalComponent. This issue crops up in a wide variety of circumstances and the correct fix depends on the specific problem. This post is my attempt to clarify the potential causes of this error and help folks resolve it. If you have any questions or comments about this, please start a new thread, tagging it with Code Signing so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Resolving errSecInternalComponent errors during code signing In some circumstances the codesign command might fail with the error errSecInternalComponent. For example: % codesign -s "Apple Development" "MyTrue" MyTrue: errSecInternalComponent This typically affects folks who are signing code in a nonstandard environm...

iOS:检测使用VPN或Proxy

参考链接: https://www.jianshu.com/p/c3b950dbf86a https://gist.github.com/PramodJoshi/4faad4c91f7dcb4eb9b06be8390c01db http://noodlecode.net/2018/04/check-if-ios-app-is-connected-to-vpn 第一种方法 需要导入框架CFNetwork 然后,这个方法是mrc的:需要添加-fno-objc-arc的flag 代码如下: + ( BOOL )getProxyStatus { NSDictionary *proxySettings = NSMakeCollectable ([( NSDictionary *) CFNetworkCopySystemProxySettings () autorelease]); NSArray *proxies = NSMakeCollectable ([( NSArray *) CFNetworkCopyProxiesForURL (( CFURLRef )[ NSURL URLWithString: @"http://www.google.com" ], ( CFDictionaryRef )proxySettings) autorelease]); NSDictionary *settings = [proxies objectAtIndex: 0 ]; NSLog ( @"host=%@" , [settings objectForKey:( NSString *)kCFProxyHostNameKey]); NSLog ( @"port=%@" , [settings objectForKey:( NSString *)kCFProxyPortNumberKey]); NSLog ( @"type=%@" , [settings objectForKey:( NSString *)kCFProxyTypeKey]); if ([[settings object...

去广告DNS设置,国内ADGuard DNS方案,手机电脑iOS去广告,保护隐私

 原文链接 之前分享过使用mac系统搭建adguard home,这几个月用下来零零散散基本上也被弃用了。主要原因是因为需要保持电脑一直开机。但是我的电脑是笔记本,存在移动各个地域的情况,也就是说只能够屏蔽电脑自身,对于手机而言不太现实。今天偶然发现dnspod推出了高级版的公共解析。dnspod背靠腾讯云,肯定是合法合规的公共解析服务,这个高级版用起来不错。 国内自己搭建解析服务是违法行为,所以这也是为什么使用dnspod的原因。 后台截图 开始使用 首先我们先进入dnspod的公共解析页面,点击开始使用。 专业版公共解析 dnspod会提供几种预设,我们选择「开发者」即可 开发者 然后你就成功的申请到自己个人使用的dns了! 更新拦截规则 我们可以将常见的广告过滤规则加入到dns中。我们在顶部选项卡中选择「拦截规则」。 拦截规则设置 打开adguard adguard 绑定iOS设备 推荐使用描述文件的方式,删除配置时删除描述文件即可。 描述文件 绑定macOS 推荐使用描述文件的方式,删除配置时删除描述文件即可。 描述文件 mac需要在「系统偏好设置」的「网络」中查看是否正在运行。 代理 如果没有运行需要点击「···」来启动服务。 启动服务 绑定路由器 找到自己路由器的DHCP设置,修改dns,然后记得绑定自己的ip。 修改dns 绑定ip 费用 目前有300万次/月的免费额度,但没有超出之后的价格。300万次一个人比较难用完,可以放心使用。 我个人使用iOS设备两台、智能家居、电脑两台,日均请求数大致2万/日。 判断是否搭建成功 可以通过查看日志的方式,日志大概有半小时到一小时的延迟,请耐心等待。