この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AWS事業本部 梶原@福岡オフィスです。
FTPSサーバを立てる機会があり、ちょっと証明書やらポート設定やらでつまづいてしまったので、次回一発でたてれるようにAnsible Playbookを作成しましたので共有します。
といっても、0からプレイブックを作成したわけでなく、vsFTPdを使用し、vsFTPdの設定はAnsible Galaxyに登録されている(https://galaxy.ansible.com/weareinteractive/vsftpd)を使用して、証明書の作成とvsftpdの設定を行っています。
では、Ansibleでもサクサクいきます。
事前準備
- ansibleのインストール(pip等でインストールを実施してください)
- AWS Configure等を実施してAWSの認証設定を行います。
- weareinteractive/vsftpd をAnsible Galaxyからインストール
$ ansible-galaxy install weareinteractive.vsftpd
roles(環境変数:roles_path)の配下にweareinteractive.vsftpd
また、依存しているweareinteractive.openssl
がダウンロードされます
EC2をAnsibleで立てる
せっかくなのでAnsibleでAWS上にEC2を立ててみようと思います。
すでに構築してあるEC2に対して実施する場合は本項はスキップしてください
構成はシンプルにパブリックサブネットにAmazon Linux2のインスタンスを立て、EIPを割り当てます。
Ansible Playbookでは
- 鍵作成
- VPC
- サブネット
- ルートテーブル
- インターネットゲートウェイ
- Elastic IP
- セキュリティグループ
- EC2(Amazon Linux2)
を行います。 セキュリティグループはSSH用の22番ポート、またFTPSように21番ポート, 50000-50010を開けています。 プレイブックは下記になります。 パラメータとして、秘密鍵またアクセス元のIPをvarsで定義しているので適時変更してください
- 秘密鍵:key_name
- アクセス元のIPアドレス:ipaddress
PlayBook(EC2作成)
# ansible-playbook aws-ftps.yml
- hosts: localhost
connection: local
gather_facts: False
become: False
vars:
region: ap-northeast-1
ipaddress: XXX.XXX.XXX.XXX/32
key_name: ec2-ftps
tasks:
- ec2_key:
region: "{{ region }}"
name: "{{ key_name }}"
register: _key
- copy:
content: "{{ _key.key.private_key }}"
dest: "~/.ssh/{{ _key.key.name }}.pem"
mode: 0600
when: _key.changed
- ec2_vpc_net:
region: "{{ region }}"
name: vpc-ftps
cidr_block: 10.0.0.0/16
register: _vpc
- ec2_vpc_igw:
region: "{{ region }}"
vpc_id: "{{ _vpc.vpc.id }}"
register: _igw
- ec2_vpc_subnet:
region: "{{ region }}"
vpc_id: "{{ _vpc.vpc.id }}"
cidr: 10.0.0.0/24
register: _subnet
- ec2_vpc_route_table:
region: "{{ region }}"
vpc_id: "{{ _vpc.vpc.id }}"
tags:
Name: Public
subnets:
- "{{ _subnet.subnet.id }}"
routes:
- dest: 0.0.0.0/0
gateway_id: "{{ _igw.gateway_id }}"
register: _public_route_table
# Security Group
- ec2_group:
region: "{{ region }}"
vpc_id: "{{ _vpc.vpc.id }}"
name: sg_ssh
description: sg-ssh
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: "{{ ipaddress }}"
register: _group_ssh
- ec2_group:
region: "{{ region }}"
vpc_id: "{{ _vpc.vpc.id }}"
name: sg_ftps
description: sg-ftps
rules:
- proto: tcp
from_port: 21
to_port: 21
cidr_ip: "{{ ipaddress }}"
- proto: tcp
from_port: 50000
to_port: 50010
cidr_ip: "{{ ipaddress }}"
register: _group_ftps
- ec2_instance:
name: "ftps"
key_name: "{{ key_name }}"
vpc_subnet_id: "{{ _subnet.subnet.id }}"
instance_type: t3.micro
image_id: ami-0c3fd0f5d33134a76
security_groups:
- "{{ _group_ssh.group_id}}"
- "{{ _group_ftps.group_id}}"
network:
assign_public_ip: true
register: _instance
- ec2_eip:
region: "{{ region }}"
device_id: "{{ item }}"
loop: "{{ _instance.instance_ids }}"
register: _eip
- debug:
msg: "Allocated IP is {{ _eip.results[0].public_ip }}"
実行結果
ansible-playbook aws-ftps.yml
<<略>>
TASK [debug] ********************************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "Allocated IP is AAA.AAA.AAA.AAA"
}
正常にAnsible Playbookが実行されますとEIPが割り当てられているので、(ここではAAA.AAA.AAA.AAA)こちらをhostsに設定します。
ssh_config
Host ftps
Hostname AAA.AAA.AAA.AAA
User ec2-user
hosts
[all]
ftps
接続確認
$ ssh -F ssh_config ftps
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
No packages needed for security; 6 packages available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-10-0-0-140 ~]$ logout
vsftpd-ftps.ymlを証明書の各値を環境、設定するドメインに合わせて書き換えてください。 各値の設定内容はOpenssl、またvsFTPDの設定項目に準拠しています。
主な設定内容としては
- openssl_self_signed: 部分の作成したい証明書の内容
- vsftpd_users: 接続するユーザ/パスワード
- vsftpd_config: vsftpd.confの内容そのままです。プロトコル等を変更してください
- pasv_addressは作成したEIPを設定します
になるかと思いますので、サーバ構成にあわせて変更お願いします。
vsftpd-ftps.yml
# ansible-playbook vsftpd-ftps.yml
- hosts: all
vars:
# 自己証明書作成
openssl_keys_path: /etc/pki/tls/private
openssl_certs_path: /etc/pki/tls/private
openssl_csrs_path: /etc/pki/tls/private
openssl_default_key_owner: root
openssl_default_key_group: root
openssl_default_cert_owner: root
openssl_default_cert_group: root
openssl_generate_csr: yes
openssl_self_signed:
- name: ftp.classmethod.info
subject:
C: JP
ST: Tokyo
L: Chiyoda-ku
O: Classmethod,Inc.
CN: ftp.classmethod.info
emailAddress: hogefuga@classmethod.jp
# FTP用 User 追加
vsftpd_users:
- username: ftpuser
name: FTP User
password: "{{ 'ftpuser' | password_hash('sha256', 'mysecretsalt') }}" # パスワード変更
# vsFTPD設定
vsftpd_config:
anonymous_enable: NO
local_enable: YES
write_enable: YES
allow_writeable_chroot: YES
dirmessage_enable: NO
ascii_upload_enable: YES
ascii_download_enable: YES
chroot_local_user: YES
tcp_wrappers: NO
connect_from_port_20: NO
xferlog_std_format: NO
pasv_enable: YES
pasv_addr_resolve: YES
pasv_address: AAA.AAA.AAA.AAA # 割り当てられたElasticIpアドレスに変更
pasv_min_port: 50000
pasv_max_port: 50010
use_localtime: YES
force_dot_files: YES
# userlist_deny: NO
listen: YES
listen_ipv6: NO
# FTP(s) 設定
ssl_enable: YES
ssl_sslv2: NO
ssl_sslv3: NO
ssl_tlsv1: YES
ssl_tlsv1_1: YES
ssl_tlsv1_2: YES
force_local_data_ssl: YES
force_local_logins_ssl: YES
# log_ftp_protocol: YES
# ssl key
vsftpd_key_file: "ftp.classmethod.info.key"
# ssl cert
vsftpd_cert_file: "ftp.classmethod.info.crt"
roles:
- weareinteractive.openssl
- weareinteractive.vsftpd
Ansible Playbookの実行
各項目を変更してAnsible Playbookをながします。
ansible-playbook vsftpd-ftps.yml
PLAY [all] **********************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************************************************************ok: [ftps]
TASK [weareinteractive.openssl : Including variables] ***************************************************************************************************************************************************************************ok: [ftps] =>
TASK [weareinteractive.openssl : Installing packages] ***************************************************************************************************************************************************************************changed: [ftps]
TASK [weareinteractive.openssl : Installing python packages] ********************************************************************************************************************************************************************changed: [ftps]
TASK [weareinteractive.openssl : Checking dir exists] ***************************************************************************************************************************************************************************ok: [ftps]
TASK [weareinteractive.openssl : Creating directory] ****************************************************************************************************************************************************************************skipping: [ftps]
TASK [weareinteractive.openssl : Checking dir exists] ***************************************************************************************************************************************************************************ok: [ftps]
TASK [weareinteractive.openssl : Creating directory] ****************************************************************************************************************************************************************************skipping: [ftps]
TASK [weareinteractive.openssl : Checking dir exists] ***************************************************************************************************************************************************************************ok: [ftps]
TASK [weareinteractive.openssl : Creating directory] ****************************************************************************************************************************************************************************skipping: [ftps]
TASK [weareinteractive.openssl : Configuring] ***********************************************************************************************************************************************************************************changed: [ftps]
TASK [weareinteractive.openssl : Copying keys] **********************************************************************************************************************************************************************************
TASK [weareinteractive.openssl : Copying certs] *********************************************************************************************************************************************************************************
TASK [weareinteractive.openssl : Creating self-signed private keys] *************************************************************************************************************************************************************changed: [ftps] => (item={'name': 'ftp.classmethod.info', 'subject': {'C': 'JP', 'ST': 'Tokyo', 'L': 'Chiyoda-ku', 'O': 'Classmethod,Inc.', 'CN': 'ftp.classmethod.info', 'emailAddress': 'hogefuga@classmethod.jp'}})
TASK [weareinteractive.openssl : Creating self-signed CSRs] *********************************************************************************************************************************************************************changed: [ftps] => (item={'name': 'ftp.classmethod.info', 'subject': {'C': 'JP', 'ST': 'Tokyo', 'L': 'Chiyoda-ku', 'O': 'Classmethod,Inc.', 'CN': 'ftp.classmethod.info', 'emailAddress': 'hogefuga@classmethod.jp'}})
TASK [weareinteractive.openssl : Generate a Self Signed OpenSSL certificate.] ***************************************************************************************************************************************************changed: [ftps] => (item={'name': 'ftp.classmethod.info', 'subject': {'C': 'JP', 'ST': 'Tokyo', 'L': 'Chiyoda-ku', 'O': 'Classmethod,Inc.', 'CN': 'ftp.classmethod.info', 'emailAddress': 'hogefuga@classmethod.jp'}})
TASK [weareinteractive.openssl : Create directory for CAcert certificates] ******************************************************************************************************************************************************skipping: [ftps]
TASK [weareinteractive.openssl : Download CAcert Class 1 PKI key] ***************************************************************************************************************************************************************skipping: [ftps]
TASK [weareinteractive.openssl : Download CAcert Class 3 PKI key] ***************************************************************************************************************************************************************skipping: [ftps]
TASK [weareinteractive.openssl : Update ca certificates to enable CAcert] *******************************************************************************************************************************************************skipping: [ftps]
TASK [weareinteractive.vsftpd : Includeing OS specific variables] ***************************************************************************************************************************************************************ok: [ftps]
TASK [weareinteractive.vsftpd : Installing packages] ****************************************************************************************************************************************************************************changed: [ftps]
TASK [weareinteractive.vsftpd : Configuring vsftp] ******************************************************************************************************************************************************************************changed: [ftps]
TASK [weareinteractive.vsftpd : Adding nologin shell] ***************************************************************************************************************************************************************************changed: [ftps]
TASK [weareinteractive.vsftpd : Setting SELinux booleans] ***********************************************************************************************************************************************************************
TASK [weareinteractive.vsftpd : Managing users] *********************************************************************************************************************************************************************************changed: [ftps] => (item={'username': 'ftpuser', 'name': 'FTP User', 'password': '$5$mysecretsalt$xxxxxxxxxxxxxxxxx'})
TASK [weareinteractive.vsftpd : Configuring service] ****************************************************************************************************************************************************************************changed: [ftps]
RUNNING HANDLER [weareinteractive.vsftpd : restart vsftpd] **********************************************************************************************************************************************************************changed: [ftps]
PLAY RECAP **********************************************************************************************************************************************************************************************************************ftps : ok=18 changed=12 unreachable=0 failed=0
接続確認
各FTPクライアントから接続確認を実施します。 とくに特別なクライアントからじゃないと接続できないとかいうことはないので割愛します。 注意事項としては
- クライアントがサポートしているプロトコルの確認
- 自己証明を使用しているためクライアント側で証明書のチェックを無効
- passiveモードでの接続
などをご注意ください。
まとめ
SFTPについては、AWSにはマネージドサービスのAWS Transfer for SFTP(https://aws.amazon.com/jp/sftp/) があるのですが、FTPまたFTPSサーバを立てる機会もまだあるかと思います。 また 【AWS】AWSでFTPサーバー立てる時に気をつけるべき2つのこと+α に沿って気をつけても、結構設定もれしていたりして子ハマりするので、次回からはサクッと終わらせれそうです。
参考
weareinteractive/ansible-vsftpd https://github.com/weareinteractive/ansible-vsftpd