├── .gitignore
├── README.md
├── burp
├── Dockerfile
├── conf
│ └── burp.config
├── entrypoint.sh
├── keys
│ └── .gitkeep
├── pkg
│ └── .gitkeep
└── run.sh
├── certbot
├── certbot-dns-burp
│ ├── Dockerfile
│ ├── LICENSE.txt
│ ├── MANIFEST.in
│ ├── README.rst
│ ├── certbot_dns_cloudflare
│ │ ├── __init__.py
│ │ ├── dns_cloudflare.py
│ │ └── dns_cloudflare_test.py
│ ├── docs
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── api.rst
│ │ ├── api
│ │ │ └── dns_cloudflare.rst
│ │ ├── conf.py
│ │ ├── index.rst
│ │ └── make.bat
│ ├── local-oldest-requirements.txt
│ ├── readthedocs.org.requirements.txt
│ ├── setup.cfg
│ └── setup.py
├── certificaterenewal.sh
├── letsencrypt
│ └── .gitkeep
├── logs
│ └── .gitkeep
├── new.sh
└── renew.sh
└── init.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | /burp/pkg/*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Burp Collaborator Server docker container with LetsEncrypt certificate
2 |
3 | This repository includes a set of scripts to install a Burp Collaborator Server in a docker environment, using a LetsEncrypt wildcard certificate.
4 | The objective is to simplify as much as possible the process of setting up and maintaining the server.
5 |
6 | ## Setup your domain
7 | Delegate a domain or subdomain to your soon-to-be burp collaborator server IP address. At the minimum you'll need an NS record for the domain/subdomain to be used.
8 |
9 | For example, if your collaborator domain is `burpserver.example`, you need to make NS records pointing with an A record to the public IP of the server: `1.2.3.4`
10 |
11 | Here as an example `dig` command to confirm:
12 | ```bash
13 | dig NS burpserver.example
14 |
15 | Output:
16 | ; <<>> DiG 9.10.6 <<>> NS burpserver.example
17 | ;; global options: +cmd
18 | ;; Got answer:
19 | ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49449
20 | ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 3
21 |
22 | ;; OPT PSEUDOSECTION:
23 | ; EDNS: version: 0, flags:; udp: 4000
24 | ;; QUESTION SECTION:
25 | ;burpserver.example. IN NS
26 |
27 | ;; ANSWER SECTION:
28 | burpserver.example. 308 IN NS ns2.burpserver.example.
29 | burpserver.example. 308 IN NS ns1.burpserver.example.
30 |
31 | ;; ADDITIONAL SECTION:
32 | ns2.burpserver.example. 308 IN A 1.2.3.4
33 | ns1.burpserver.example. 308 IN A 1.2.3.4
34 |
35 | ;; Query time: 52 msec
36 | ;; SERVER: 8.8.8.8#53(8.8.8.8)
37 | ;; WHEN: Fri Jul 12 11:20:29 EDT 2024
38 | ;; MSG SIZE rcvd: 104
39 | ```
40 |
41 | Check https://portswigger.net/burp/documentation/collaborator/deploying#dns-configuration for further info.
42 |
43 | ## Requirements
44 |
45 | * Internet accessible server
46 | * bash
47 | * docker
48 | * bc
49 | * openssl
50 | * Burp Suite Professional
51 |
52 | ## Setup the environment
53 |
54 | * Clone or download the repository to the server (tested on ubuntu 16.04) to a directory of your choice.
55 | * Put the Burp Suite JAR file in ```./burp/pkg/burp.jar``` (make sure the name is exactly ```burp.jar```, and it is the actual file **not a link**)
56 | * Run init.sh with your subdomain and server public IP address as argument:
57 |
58 | ```./init.sh burp.example.com 1.2.3.4```
59 |
60 | This will start the environment for the subdomain ```burp.example.com```, creating a wildcard certificate as ```*.burp.example.com```.
61 |
62 | I'm using an ugly hack on the certbot-dns-cloudflare plugin from certbot, where it just runs a local dnsmasq with the required records, and makes
63 | all of this automagically happen.
64 |
65 | If everything is OK, burp will start with the following message:
66 |
67 | > Burp is now running with the letsencrypt certificate for domain *.burp.example.com
68 |
69 | You can check by running ```docker ps```, and going to burp, and pointing the collaborator configuration to your new server.
70 | Keep it mind that this configuration configures the *polling server on port 9443*.
71 |
72 | The init.sh script will be renamed and disabled, so no accidents may happen.
73 |
74 | ## Certificate renewal
75 |
76 | * There's a renewal script in ```./certbot/certificaterenewal.sh```. When run, it renews the certificate if it expires in 30 days or less;
77 | * Optionally, edit the RENEWDAYS variable if you wish to. By default it will renew the certificate every 60 days. *If you want to force the renewal to check if everything is working, just set it to 89 days, and run it manually. Remember to set it back to 60 afterwards.*;
78 | * Set your crontab to run this script once a day.
79 |
80 | ## Updating Burp Suite
81 |
82 | * Download it and make sure you put it in ```./burp/pkg/burp.jar```
83 | * Restart the container with ```docker restart burp```
84 |
85 | ## Docker and UFW
86 | If you use UFW/IPTables as your firewall on the host, both UFW and docker modify the same [iptables](https://en.wikipedia.org/wiki/Iptables "iptables") configurations. Whatever UFW rules you have set, running a docker container completely ignores them and allows traffic, regardless of whether you explicitly block access. In order to fix the issue and be able to use UFW properly with docker, read this:
87 |
88 | https://blog.jarrousse.org/2023/03/18/how-to-use-ufw-firewall-with-docker-containers/
89 |
90 | These instructions assume you have the default docker set up and didn't try to fix the problem yourself yet.
91 | **Download `ufw-docker` script**
92 | ```bash
93 | sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
94 | sudo chmod +x /usr/local/bin/ufw-docker
95 | ```
96 |
97 | Then using the following command to modify the `after.rules` file of `ufw`
98 | ```bash
99 | ufw-docker install
100 | ```
101 |
102 | reboot the host and check if you can access the ports of your container.
103 |
104 | Now allow the traffic to the ports on the containers
105 | - Use the actual port thats open on the container, not the one its binded to on the host
106 | - `burp` is the container name, so thats what we use with below command
107 | ```bash
108 | docker ps -a
109 | sudo ufw-docker allow burp 8443
110 | ```
111 |
112 |
113 | I have provided the commands conventiently for you here:
114 | ```bash
115 | sudo ufw-docker allow burp 8053
116 | sudo ufw-docker allow burp 8053/udp
117 | sudo ufw-docker allow burp 8080
118 | sudo ufw-docker allow burp 8443
119 | sudo ufw-docker allow burp 8465
120 | sudo ufw-docker allow burp 8587
121 | sudo ufw-docker allow burp 8080
122 | ```
123 |
124 | I HIGHLY recommend restricting access to your polling port from an IP address or network. Don't allow the general internet to use your burp collab server for free!
125 | - `your_whitelisted_ip` is your public IP to allow access from
126 | - `your_containers_local_ip` is 172.x.x.x
127 |
128 | ```bash
129 | ufw route allow proto tcp from your_whitelisted_ip to your_containers_local_ip port 9443
130 | ```
131 |
132 | You should be good to go and have your UFW locked down!
133 |
134 | ---
135 | **Author:** [Bruno Morisson](https://twitter.com/morisson)
136 |
137 | Thanks to [Fábio Pires](https://twitter.com/fabiopirespt) (check his burp collaborator w/letsencrypt [tutorial](https://blog.fabiopires.pt/running-your-instance-of-burp-collaborator-server/)) and [Herman Duarte](https://twitter.com/hdontwit) (for betatesting and fixes)
138 |
139 |
140 |
--------------------------------------------------------------------------------
/burp/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM debian:bullseye-slim
2 |
3 | RUN apt-get update && \
4 | apt-get -yqq dist-upgrade
5 |
6 | # Install wget to download JDK
7 | RUN apt-get -yqq install wget && \
8 | apt-get autoremove -yqq && \
9 | apt-get clean && \
10 | /bin/rm -rf /var/lib/apt/lists/*
11 |
12 | # Download and install Oracle JDK 21
13 | RUN wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.deb && \
14 | dpkg -i jdk-21_linux-x64_bin.deb && \
15 | rm jdk-21_linux-x64_bin.deb
16 |
17 | # Create a user and group for Burp
18 | RUN groupadd -g 999 burp && \
19 | useradd -r -u 999 -g burp -d /opt/burp burp
20 |
21 | # Switch to the burp user
22 | USER burp
23 |
24 | ADD entrypoint.sh /opt/burp/entrypoint.sh
25 | WORKDIR /opt/burp
26 | ENTRYPOINT ["/opt/burp/entrypoint.sh"]
27 |
--------------------------------------------------------------------------------
/burp/conf/burp.config:
--------------------------------------------------------------------------------
1 | {
2 | "serverDomain" : "DOMAIN",
3 | "workerThreads" : 40,
4 |
5 | "eventCapture": {
6 | "localAddress" : ["0.0.0.0"],
7 | "publicAddress": ["IP"],
8 |
9 | "http": {
10 | "port" : 8080
11 | },
12 |
13 | "https": {
14 | "port" : 8443,
15 | "certificateFiles" : [
16 | "/opt/burp/keys/privkey.pem",
17 | "/opt/burp/keys/cert.pem",
18 | "/opt/burp/keys/fullchain.pem"
19 | ]
20 | },
21 |
22 | "smtp": {
23 | "ports": [8025,8587]
24 | },
25 | "smtps": {
26 | "port": 8465,
27 | "certificateFiles" : [
28 | "/opt/burp/keys/privkey.pem",
29 | "/opt/burp/keys/cert.pem",
30 | "/opt/burp/keys/fullchain.pem"
31 | ]
32 | }
33 | },
34 |
35 | "polling" : {
36 | "localAddress" : "0.0.0.0",
37 | "http": {
38 | "localAddress" : "0.0.0.0",
39 | "publicAddress": ["IP"],
40 | "port" : 9090
41 | },
42 |
43 | "https": {
44 | "port" : 9443,
45 | "localAddress" : "0.0.0.0",
46 | "publicAddress": ["IP"],
47 | "certificateFiles" : [
48 | "/opt/burp/keys/privkey.pem",
49 | "/opt/burp/keys/cert.pem",
50 | "/opt/burp/keys/fullchain.pem"
51 | ]
52 | }
53 | },
54 |
55 | "metrics": {
56 | "path" : "jnaicmez8",
57 | "addressWhitelist" : ["127.0.0.1/32"]
58 | },
59 |
60 | "dns": {
61 | "interfaces" : [{
62 | "publicAddress": ["IP"],
63 | "localAddress":"0.0.0.0",
64 | "name":"ns1"
65 | }],
66 | "port" : 8053,
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/burp/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd /opt/burp
3 | exec java -jar /opt/burp/pkg/burp.jar --collaborator-server --collaborator-config=/opt/burp/conf/burp.config
4 |
--------------------------------------------------------------------------------
/burp/keys/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devoteam-cybertrust/burpcollaborator-docker/385e70115dc5eb43e78c7d7e99bd8fed7f8119d2/burp/keys/.gitkeep
--------------------------------------------------------------------------------
/burp/pkg/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devoteam-cybertrust/burpcollaborator-docker/385e70115dc5eb43e78c7d7e99bd8fed7f8119d2/burp/pkg/.gitkeep
--------------------------------------------------------------------------------
/burp/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | echo Starting burp... && \
3 | docker run -d --restart=always --name burp --hostname burp -p 53:8053 -p 53:8053/udp -p 80:8080 -p 443:8443 -p 25:8025 -p 587:8587 -p 465:8465 -p 9090:9090 -p 9443:9443 -v $PWD/burp/keys:/opt/burp/keys:ro -v $PWD/burp/conf:/opt/burp/conf:ro -v $PWD/burp/pkg:/opt/burp/pkg:ro burp && \
4 | echo Done.
5 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM certbot/certbot
2 |
3 | COPY . src/certbot-dns-cloudflare
4 |
5 | RUN pip install --no-cache-dir --editable src/certbot-dns-cloudflare
6 |
7 | # INSTALL DNSMASQ
8 | RUN apk add dnsmasq
9 | RUN echo 'conf-dir=/etc/dnsmasq.d/,*.conf' > /etc/dnsmasq.conf
10 | RUN echo "user=root" >> /etc/dnsmasq.conf
11 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2015 Electronic Frontier Foundation and others
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
15 | Apache License
16 | Version 2.0, January 2004
17 | http://www.apache.org/licenses/
18 |
19 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
20 |
21 | 1. Definitions.
22 |
23 | "License" shall mean the terms and conditions for use, reproduction,
24 | and distribution as defined by Sections 1 through 9 of this document.
25 |
26 | "Licensor" shall mean the copyright owner or entity authorized by
27 | the copyright owner that is granting the License.
28 |
29 | "Legal Entity" shall mean the union of the acting entity and all
30 | other entities that control, are controlled by, or are under common
31 | control with that entity. For the purposes of this definition,
32 | "control" means (i) the power, direct or indirect, to cause the
33 | direction or management of such entity, whether by contract or
34 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
35 | outstanding shares, or (iii) beneficial ownership of such entity.
36 |
37 | "You" (or "Your") shall mean an individual or Legal Entity
38 | exercising permissions granted by this License.
39 |
40 | "Source" form shall mean the preferred form for making modifications,
41 | including but not limited to software source code, documentation
42 | source, and configuration files.
43 |
44 | "Object" form shall mean any form resulting from mechanical
45 | transformation or translation of a Source form, including but
46 | not limited to compiled object code, generated documentation,
47 | and conversions to other media types.
48 |
49 | "Work" shall mean the work of authorship, whether in Source or
50 | Object form, made available under the License, as indicated by a
51 | copyright notice that is included in or attached to the work
52 | (an example is provided in the Appendix below).
53 |
54 | "Derivative Works" shall mean any work, whether in Source or Object
55 | form, that is based on (or derived from) the Work and for which the
56 | editorial revisions, annotations, elaborations, or other modifications
57 | represent, as a whole, an original work of authorship. For the purposes
58 | of this License, Derivative Works shall not include works that remain
59 | separable from, or merely link (or bind by name) to the interfaces of,
60 | the Work and Derivative Works thereof.
61 |
62 | "Contribution" shall mean any work of authorship, including
63 | the original version of the Work and any modifications or additions
64 | to that Work or Derivative Works thereof, that is intentionally
65 | submitted to Licensor for inclusion in the Work by the copyright owner
66 | or by an individual or Legal Entity authorized to submit on behalf of
67 | the copyright owner. For the purposes of this definition, "submitted"
68 | means any form of electronic, verbal, or written communication sent
69 | to the Licensor or its representatives, including but not limited to
70 | communication on electronic mailing lists, source code control systems,
71 | and issue tracking systems that are managed by, or on behalf of, the
72 | Licensor for the purpose of discussing and improving the Work, but
73 | excluding communication that is conspicuously marked or otherwise
74 | designated in writing by the copyright owner as "Not a Contribution."
75 |
76 | "Contributor" shall mean Licensor and any individual or Legal Entity
77 | on behalf of whom a Contribution has been received by Licensor and
78 | subsequently incorporated within the Work.
79 |
80 | 2. Grant of Copyright License. Subject to the terms and conditions of
81 | this License, each Contributor hereby grants to You a perpetual,
82 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
83 | copyright license to reproduce, prepare Derivative Works of,
84 | publicly display, publicly perform, sublicense, and distribute the
85 | Work and such Derivative Works in Source or Object form.
86 |
87 | 3. Grant of Patent License. Subject to the terms and conditions of
88 | this License, each Contributor hereby grants to You a perpetual,
89 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
90 | (except as stated in this section) patent license to make, have made,
91 | use, offer to sell, sell, import, and otherwise transfer the Work,
92 | where such license applies only to those patent claims licensable
93 | by such Contributor that are necessarily infringed by their
94 | Contribution(s) alone or by combination of their Contribution(s)
95 | with the Work to which such Contribution(s) was submitted. If You
96 | institute patent litigation against any entity (including a
97 | cross-claim or counterclaim in a lawsuit) alleging that the Work
98 | or a Contribution incorporated within the Work constitutes direct
99 | or contributory patent infringement, then any patent licenses
100 | granted to You under this License for that Work shall terminate
101 | as of the date such litigation is filed.
102 |
103 | 4. Redistribution. You may reproduce and distribute copies of the
104 | Work or Derivative Works thereof in any medium, with or without
105 | modifications, and in Source or Object form, provided that You
106 | meet the following conditions:
107 |
108 | (a) You must give any other recipients of the Work or
109 | Derivative Works a copy of this License; and
110 |
111 | (b) You must cause any modified files to carry prominent notices
112 | stating that You changed the files; and
113 |
114 | (c) You must retain, in the Source form of any Derivative Works
115 | that You distribute, all copyright, patent, trademark, and
116 | attribution notices from the Source form of the Work,
117 | excluding those notices that do not pertain to any part of
118 | the Derivative Works; and
119 |
120 | (d) If the Work includes a "NOTICE" text file as part of its
121 | distribution, then any Derivative Works that You distribute must
122 | include a readable copy of the attribution notices contained
123 | within such NOTICE file, excluding those notices that do not
124 | pertain to any part of the Derivative Works, in at least one
125 | of the following places: within a NOTICE text file distributed
126 | as part of the Derivative Works; within the Source form or
127 | documentation, if provided along with the Derivative Works; or,
128 | within a display generated by the Derivative Works, if and
129 | wherever such third-party notices normally appear. The contents
130 | of the NOTICE file are for informational purposes only and
131 | do not modify the License. You may add Your own attribution
132 | notices within Derivative Works that You distribute, alongside
133 | or as an addendum to the NOTICE text from the Work, provided
134 | that such additional attribution notices cannot be construed
135 | as modifying the License.
136 |
137 | You may add Your own copyright statement to Your modifications and
138 | may provide additional or different license terms and conditions
139 | for use, reproduction, or distribution of Your modifications, or
140 | for any such Derivative Works as a whole, provided Your use,
141 | reproduction, and distribution of the Work otherwise complies with
142 | the conditions stated in this License.
143 |
144 | 5. Submission of Contributions. Unless You explicitly state otherwise,
145 | any Contribution intentionally submitted for inclusion in the Work
146 | by You to the Licensor shall be under the terms and conditions of
147 | this License, without any additional terms or conditions.
148 | Notwithstanding the above, nothing herein shall supersede or modify
149 | the terms of any separate license agreement you may have executed
150 | with Licensor regarding such Contributions.
151 |
152 | 6. Trademarks. This License does not grant permission to use the trade
153 | names, trademarks, service marks, or product names of the Licensor,
154 | except as required for reasonable and customary use in describing the
155 | origin of the Work and reproducing the content of the NOTICE file.
156 |
157 | 7. Disclaimer of Warranty. Unless required by applicable law or
158 | agreed to in writing, Licensor provides the Work (and each
159 | Contributor provides its Contributions) on an "AS IS" BASIS,
160 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
161 | implied, including, without limitation, any warranties or conditions
162 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
163 | PARTICULAR PURPOSE. You are solely responsible for determining the
164 | appropriateness of using or redistributing the Work and assume any
165 | risks associated with Your exercise of permissions under this License.
166 |
167 | 8. Limitation of Liability. In no event and under no legal theory,
168 | whether in tort (including negligence), contract, or otherwise,
169 | unless required by applicable law (such as deliberate and grossly
170 | negligent acts) or agreed to in writing, shall any Contributor be
171 | liable to You for damages, including any direct, indirect, special,
172 | incidental, or consequential damages of any character arising as a
173 | result of this License or out of the use or inability to use the
174 | Work (including but not limited to damages for loss of goodwill,
175 | work stoppage, computer failure or malfunction, or any and all
176 | other commercial damages or losses), even if such Contributor
177 | has been advised of the possibility of such damages.
178 |
179 | 9. Accepting Warranty or Additional Liability. While redistributing
180 | the Work or Derivative Works thereof, You may choose to offer,
181 | and charge a fee for, acceptance of support, warranty, indemnity,
182 | or other liability obligations and/or rights consistent with this
183 | License. However, in accepting such obligations, You may act only
184 | on Your own behalf and on Your sole responsibility, not on behalf
185 | of any other Contributor, and only if You agree to indemnify,
186 | defend, and hold each Contributor harmless for any liability
187 | incurred by, or claims asserted against, such Contributor by reason
188 | of your accepting any such warranty or additional liability.
189 |
190 | END OF TERMS AND CONDITIONS
191 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE.txt
2 | include README.rst
3 | recursive-include docs *
4 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/README.rst:
--------------------------------------------------------------------------------
1 | Cloudflare DNS Authenticator plugin for Certbot
2 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/certbot_dns_cloudflare/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | The `~certbot_dns_cloudflare.dns_cloudflare` plugin automates the process of
3 | completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
4 | subsequently removing, TXT records using the Cloudflare API.
5 |
6 |
7 | Named Arguments
8 | ---------------
9 |
10 | ======================================== =====================================
11 | ``--dns-cloudflare-credentials`` Cloudflare credentials_ INI file.
12 | (Required)
13 | ``--dns-cloudflare-propagation-seconds`` The number of seconds to wait for DNS
14 | to propagate before asking the ACME
15 | server to verify the DNS record.
16 | (Default: 10)
17 | ======================================== =====================================
18 |
19 |
20 | Credentials
21 | -----------
22 |
23 | Use of this plugin requires a configuration file containing Cloudflare API
24 | credentials, obtained from your Cloudflare
25 | `account page `_.
26 |
27 | .. code-block:: ini
28 | :name: credentials.ini
29 | :caption: Example credentials file:
30 |
31 | # Cloudflare API credentials used by Certbot
32 | dns_cloudflare_email = cloudflare@example.com
33 | dns_cloudflare_api_key = 0123456789abcdef0123456789abcdef01234567
34 |
35 | The path to this file can be provided interactively or using the
36 | ``--dns-cloudflare-credentials`` command-line argument. Certbot records the path
37 | to this file for use during renewal, but does not store the file's contents.
38 |
39 | .. caution::
40 | You should protect these API credentials as you would the password to your
41 | Cloudflare account. Users who can read this file can use these credentials
42 | to issue arbitrary API calls on your behalf. Users who can cause Certbot to
43 | run using these credentials can complete a ``dns-01`` challenge to acquire
44 | new certificates or revoke existing certificates for associated domains,
45 | even if those domains aren't being managed by this server.
46 |
47 | Certbot will emit a warning if it detects that the credentials file can be
48 | accessed by other users on your system. The warning reads "Unsafe permissions
49 | on credentials configuration file", followed by the path to the credentials
50 | file. This warning will be emitted each time Certbot uses the credentials file,
51 | including for renewal, and cannot be silenced except by addressing the issue
52 | (e.g., by using a command like ``chmod 600`` to restrict access to the file).
53 |
54 |
55 | Examples
56 | --------
57 |
58 | .. code-block:: bash
59 | :caption: To acquire a certificate for ``example.com``
60 |
61 | certbot certonly \\
62 | --dns-cloudflare \\
63 | --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \\
64 | -d example.com
65 |
66 | .. code-block:: bash
67 | :caption: To acquire a single certificate for both ``example.com`` and
68 | ``www.example.com``
69 |
70 | certbot certonly \\
71 | --dns-cloudflare \\
72 | --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \\
73 | -d example.com \\
74 | -d www.example.com
75 |
76 | .. code-block:: bash
77 | :caption: To acquire a certificate for ``example.com``, waiting 60 seconds
78 | for DNS propagation
79 |
80 | certbot certonly \\
81 | --dns-cloudflare \\
82 | --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \\
83 | --dns-cloudflare-propagation-seconds 60 \\
84 | -d example.com
85 |
86 | """
87 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/certbot_dns_cloudflare/dns_cloudflare.py:
--------------------------------------------------------------------------------
1 | """DNS Authenticator for Cloudflare."""
2 | """ Ugly hack to support burp collaborator certificates using dnsmasq
3 | IT DOES NOT WORK WITH CLOUDFLARE!!!!
4 | """
5 | import logging
6 |
7 | #import CloudFlare
8 | import zope.interface
9 |
10 | from certbot import errors
11 | from certbot import interfaces
12 | from certbot.plugins import dns_common
13 |
14 | import subprocess
15 |
16 |
17 | logger = logging.getLogger(__name__)
18 |
19 |
20 | @zope.interface.implementer(interfaces.IAuthenticator)
21 | @zope.interface.provider(interfaces.IPluginFactory)
22 | class Authenticator(dns_common.DNSAuthenticator):
23 | """DNS Authenticator for Cloudflare
24 |
25 | This Authenticator uses the Cloudflare API to fulfill a dns-01 challenge.
26 | """
27 |
28 | description = ('Obtain certificates using a DNS TXT record (if you are using Cloudflare for '
29 | 'DNS).')
30 | ttl = 120
31 | chall01 = None
32 | chall01_vn = None
33 | chall02 = None
34 | chall02_vn = None
35 |
36 |
37 | def __init__(self, *args, **kwargs):
38 | super(Authenticator, self).__init__(*args, **kwargs)
39 | self.chall01 = None
40 | self.chall01_vn = None
41 | self.chall02 = None
42 | self.chall02_vn = None
43 |
44 | def more_info(self): # pylint: disable=missing-docstring,no-self-use
45 | return 'This plugin configures a DNS TXT record to respond to a dns-01 challenge using ' + \
46 | 'the Cloudflare API.'
47 |
48 | def _setup_credentials(self):
49 | return True
50 |
51 | def _perform(self, domain, validation_name, validation):
52 | self.add_txt_record(domain, validation_name, validation)
53 |
54 | def _cleanup(self, domain, validation_name, validation):
55 | self.del_txt_record(domain, validation_name, validation)
56 |
57 |
58 | def add_txt_record(self,domain, validation_name, validation):
59 | if self.chall01:
60 | self.chall02=validation
61 | self.chall02_vn=validation_name
62 | print("Launching DNSMASQ...")
63 | self.launch_dnsmasq(domain)
64 | else:
65 | self.chall01=validation
66 | self.chall01_vn=validation_name
67 |
68 | def del_txt_record(self,domain, validation_name, validation):
69 | return True
70 |
71 | def launch_dnsmasq(self,domain):
72 | dnsmasq='/usr/sbin/dnsmasq -q --dns-rr='+domain+',257,000569737375656C657473656E63727970742E6F7267 --txt-record='+self.chall01_vn+',"'+self.chall01+'" --txt-record='+self.chall02_vn+',"'+self.chall02+'" --no-resolv --port=53'
73 | print("DNSMASQ CMD: \n{}".format(dnsmasq))
74 | subprocess.Popen(dnsmasq, shell=True, stdout=subprocess.PIPE)
75 |
76 |
77 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/certbot_dns_cloudflare/dns_cloudflare_test.py:
--------------------------------------------------------------------------------
1 | """Tests for certbot_dns_cloudflare.dns_cloudflare."""
2 |
3 | import os
4 | import unittest
5 |
6 | import CloudFlare
7 | import mock
8 |
9 | from certbot import errors
10 | from certbot.plugins import dns_test_common
11 | from certbot.plugins.dns_test_common import DOMAIN
12 | from certbot.tests import util as test_util
13 |
14 | API_ERROR = CloudFlare.exceptions.CloudFlareAPIError(1000, '', '')
15 | API_KEY = 'an-api-key'
16 | EMAIL = 'example@example.com'
17 |
18 |
19 | class AuthenticatorTest(test_util.TempDirTestCase, dns_test_common.BaseAuthenticatorTest):
20 |
21 | def setUp(self):
22 | from certbot_dns_cloudflare.dns_cloudflare import Authenticator
23 |
24 | super(AuthenticatorTest, self).setUp()
25 |
26 | path = os.path.join(self.tempdir, 'file.ini')
27 | dns_test_common.write({"cloudflare_email": EMAIL, "cloudflare_api_key": API_KEY}, path)
28 |
29 | self.config = mock.MagicMock(cloudflare_credentials=path,
30 | cloudflare_propagation_seconds=0) # don't wait during tests
31 |
32 | self.auth = Authenticator(self.config, "cloudflare")
33 |
34 | self.mock_client = mock.MagicMock()
35 | # _get_cloudflare_client | pylint: disable=protected-access
36 | self.auth._get_cloudflare_client = mock.MagicMock(return_value=self.mock_client)
37 |
38 | def test_perform(self):
39 | self.auth.perform([self.achall])
40 |
41 | expected = [mock.call.add_txt_record(DOMAIN, '_acme-challenge.'+DOMAIN, mock.ANY, mock.ANY)]
42 | self.assertEqual(expected, self.mock_client.mock_calls)
43 |
44 | def test_cleanup(self):
45 | # _attempt_cleanup | pylint: disable=protected-access
46 | self.auth._attempt_cleanup = True
47 | self.auth.cleanup([self.achall])
48 |
49 | expected = [mock.call.del_txt_record(DOMAIN, '_acme-challenge.'+DOMAIN, mock.ANY)]
50 | self.assertEqual(expected, self.mock_client.mock_calls)
51 |
52 |
53 | class CloudflareClientTest(unittest.TestCase):
54 | record_name = "foo"
55 | record_content = "bar"
56 | record_ttl = 42
57 | zone_id = 1
58 | record_id = 2
59 |
60 | def setUp(self):
61 | from certbot_dns_cloudflare.dns_cloudflare import _CloudflareClient
62 |
63 | self.cloudflare_client = _CloudflareClient(EMAIL, API_KEY)
64 |
65 | self.cf = mock.MagicMock()
66 | self.cloudflare_client.cf = self.cf
67 |
68 | def test_add_txt_record(self):
69 | self.cf.zones.get.return_value = [{'id': self.zone_id}]
70 |
71 | self.cloudflare_client.add_txt_record(DOMAIN, self.record_name, self.record_content,
72 | self.record_ttl)
73 |
74 | self.cf.zones.dns_records.post.assert_called_with(self.zone_id, data=mock.ANY)
75 |
76 | post_data = self.cf.zones.dns_records.post.call_args[1]['data']
77 |
78 | self.assertEqual('TXT', post_data['type'])
79 | self.assertEqual(self.record_name, post_data['name'])
80 | self.assertEqual(self.record_content, post_data['content'])
81 | self.assertEqual(self.record_ttl, post_data['ttl'])
82 |
83 | def test_add_txt_record_error(self):
84 | self.cf.zones.get.return_value = [{'id': self.zone_id}]
85 |
86 | self.cf.zones.dns_records.post.side_effect = API_ERROR
87 |
88 | self.assertRaises(
89 | errors.PluginError,
90 | self.cloudflare_client.add_txt_record,
91 | DOMAIN, self.record_name, self.record_content, self.record_ttl)
92 |
93 | def test_add_txt_record_error_during_zone_lookup(self):
94 | self.cf.zones.get.side_effect = API_ERROR
95 |
96 | self.assertRaises(
97 | errors.PluginError,
98 | self.cloudflare_client.add_txt_record,
99 | DOMAIN, self.record_name, self.record_content, self.record_ttl)
100 |
101 | def test_add_txt_record_zone_not_found(self):
102 | self.cf.zones.get.return_value = []
103 |
104 | self.assertRaises(
105 | errors.PluginError,
106 | self.cloudflare_client.add_txt_record,
107 | DOMAIN, self.record_name, self.record_content, self.record_ttl)
108 |
109 | def test_del_txt_record(self):
110 | self.cf.zones.get.return_value = [{'id': self.zone_id}]
111 | self.cf.zones.dns_records.get.return_value = [{'id': self.record_id}]
112 |
113 | self.cloudflare_client.del_txt_record(DOMAIN, self.record_name, self.record_content)
114 |
115 | expected = [mock.call.zones.get(params=mock.ANY),
116 | mock.call.zones.dns_records.get(self.zone_id, params=mock.ANY),
117 | mock.call.zones.dns_records.delete(self.zone_id, self.record_id)]
118 |
119 | self.assertEqual(expected, self.cf.mock_calls)
120 |
121 | get_data = self.cf.zones.dns_records.get.call_args[1]['params']
122 |
123 | self.assertEqual('TXT', get_data['type'])
124 | self.assertEqual(self.record_name, get_data['name'])
125 | self.assertEqual(self.record_content, get_data['content'])
126 |
127 | def test_del_txt_record_error_during_zone_lookup(self):
128 | self.cf.zones.get.side_effect = API_ERROR
129 |
130 | self.cloudflare_client.del_txt_record(DOMAIN, self.record_name, self.record_content)
131 |
132 | def test_del_txt_record_error_during_delete(self):
133 | self.cf.zones.get.return_value = [{'id': self.zone_id}]
134 | self.cf.zones.dns_records.get.return_value = [{'id': self.record_id}]
135 | self.cf.zones.dns_records.delete.side_effect = API_ERROR
136 |
137 | self.cloudflare_client.del_txt_record(DOMAIN, self.record_name, self.record_content)
138 | expected = [mock.call.zones.get(params=mock.ANY),
139 | mock.call.zones.dns_records.get(self.zone_id, params=mock.ANY),
140 | mock.call.zones.dns_records.delete(self.zone_id, self.record_id)]
141 |
142 | self.assertEqual(expected, self.cf.mock_calls)
143 |
144 | def test_del_txt_record_error_during_get(self):
145 | self.cf.zones.get.return_value = [{'id': self.zone_id}]
146 | self.cf.zones.dns_records.get.side_effect = API_ERROR
147 |
148 | self.cloudflare_client.del_txt_record(DOMAIN, self.record_name, self.record_content)
149 | expected = [mock.call.zones.get(params=mock.ANY),
150 | mock.call.zones.dns_records.get(self.zone_id, params=mock.ANY)]
151 |
152 | self.assertEqual(expected, self.cf.mock_calls)
153 |
154 | def test_del_txt_record_no_record(self):
155 | self.cf.zones.get.return_value = [{'id': self.zone_id}]
156 | self.cf.zones.dns_records.get.return_value = []
157 |
158 | self.cloudflare_client.del_txt_record(DOMAIN, self.record_name, self.record_content)
159 | expected = [mock.call.zones.get(params=mock.ANY),
160 | mock.call.zones.dns_records.get(self.zone_id, params=mock.ANY)]
161 |
162 | self.assertEqual(expected, self.cf.mock_calls)
163 |
164 | def test_del_txt_record_no_zone(self):
165 | self.cf.zones.get.return_value = [{'id': None}]
166 |
167 | self.cloudflare_client.del_txt_record(DOMAIN, self.record_name, self.record_content)
168 | expected = [mock.call.zones.get(params=mock.ANY)]
169 |
170 | self.assertEqual(expected, self.cf.mock_calls)
171 |
172 |
173 | if __name__ == "__main__":
174 | unittest.main() # pragma: no cover
175 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/docs/.gitignore:
--------------------------------------------------------------------------------
1 | /_build/
2 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = certbot-dns-cloudflare
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/docs/api.rst:
--------------------------------------------------------------------------------
1 | =================
2 | API Documentation
3 | =================
4 |
5 | .. toctree::
6 | :glob:
7 |
8 | api/**
9 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/docs/api/dns_cloudflare.rst:
--------------------------------------------------------------------------------
1 | :mod:`certbot_dns_cloudflare.dns_cloudflare`
2 | --------------------------------------------
3 |
4 | .. automodule:: certbot_dns_cloudflare.dns_cloudflare
5 | :members:
6 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # certbot-dns-cloudflare documentation build configuration file, created by
4 | # sphinx-quickstart on Tue May 9 10:20:04 2017.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | # If extensions (or modules to document with autodoc) are in another directory,
16 | # add these directories to sys.path here. If the directory is relative to the
17 | # documentation root, use os.path.abspath to make it absolute, like shown here.
18 | #
19 | import os
20 | # import sys
21 | # sys.path.insert(0, os.path.abspath('.'))
22 |
23 |
24 | # -- General configuration ------------------------------------------------
25 |
26 | # If your documentation needs a minimal Sphinx version, state it here.
27 | #
28 | needs_sphinx = '1.0'
29 |
30 | # Add any Sphinx extension module names here, as strings. They can be
31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
32 | # ones.
33 | extensions = ['sphinx.ext.autodoc',
34 | 'sphinx.ext.intersphinx',
35 | 'sphinx.ext.todo',
36 | 'sphinx.ext.coverage',
37 | 'sphinx.ext.viewcode']
38 |
39 | autodoc_member_order = 'bysource'
40 | autodoc_default_flags = ['show-inheritance', 'private-members']
41 |
42 | # Add any paths that contain templates here, relative to this directory.
43 | templates_path = ['_templates']
44 |
45 | # The suffix(es) of source filenames.
46 | # You can specify multiple suffix as a list of string:
47 | #
48 | # source_suffix = ['.rst', '.md']
49 | source_suffix = '.rst'
50 |
51 | # The master toctree document.
52 | master_doc = 'index'
53 |
54 | # General information about the project.
55 | project = u'certbot-dns-cloudflare'
56 | copyright = u'2017, Certbot Project'
57 | author = u'Certbot Project'
58 |
59 | # The version info for the project you're documenting, acts as replacement for
60 | # |version| and |release|, also used in various other places throughout the
61 | # built documents.
62 | #
63 | # The short X.Y version.
64 | version = u'0'
65 | # The full version, including alpha/beta/rc tags.
66 | release = u'0'
67 |
68 | # The language for content autogenerated by Sphinx. Refer to documentation
69 | # for a list of supported languages.
70 | #
71 | # This is also used if you do content translation via gettext catalogs.
72 | # Usually you set "language" from the command line for these cases.
73 | language = 'en'
74 |
75 | # List of patterns, relative to source directory, that match files and
76 | # directories to ignore when looking for source files.
77 | # This patterns also effect to html_static_path and html_extra_path
78 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
79 |
80 | default_role = 'py:obj'
81 |
82 | # The name of the Pygments (syntax highlighting) style to use.
83 | pygments_style = 'sphinx'
84 |
85 | # If true, `todo` and `todoList` produce output, else they produce nothing.
86 | todo_include_todos = True
87 |
88 |
89 | # -- Options for HTML output ----------------------------------------------
90 |
91 | # The theme to use for HTML and HTML Help pages. See the documentation for
92 | # a list of builtin themes.
93 | #
94 |
95 | # http://docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs
96 | # on_rtd is whether we are on readthedocs.org
97 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
98 | if not on_rtd: # only import and set the theme if we're building docs locally
99 | import sphinx_rtd_theme
100 | html_theme = 'sphinx_rtd_theme'
101 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
102 | # otherwise, readthedocs.org uses their theme by default, so no need to specify it
103 |
104 | # Theme options are theme-specific and customize the look and feel of a theme
105 | # further. For a list of options available for each theme, see the
106 | # documentation.
107 | #
108 | # html_theme_options = {}
109 |
110 | # Add any paths that contain custom static files (such as style sheets) here,
111 | # relative to this directory. They are copied after the builtin static files,
112 | # so a file named "default.css" will overwrite the builtin "default.css".
113 | html_static_path = ['_static']
114 |
115 |
116 | # -- Options for HTMLHelp output ------------------------------------------
117 |
118 | # Output file base name for HTML help builder.
119 | htmlhelp_basename = 'certbot-dns-cloudflaredoc'
120 |
121 |
122 | # -- Options for LaTeX output ---------------------------------------------
123 |
124 | latex_elements = {
125 | # The paper size ('letterpaper' or 'a4paper').
126 | #
127 | # 'papersize': 'letterpaper',
128 |
129 | # The font size ('10pt', '11pt' or '12pt').
130 | #
131 | # 'pointsize': '10pt',
132 |
133 | # Additional stuff for the LaTeX preamble.
134 | #
135 | # 'preamble': '',
136 |
137 | # Latex figure (float) alignment
138 | #
139 | # 'figure_align': 'htbp',
140 | }
141 |
142 | # Grouping the document tree into LaTeX files. List of tuples
143 | # (source start file, target name, title,
144 | # author, documentclass [howto, manual, or own class]).
145 | latex_documents = [
146 | (master_doc, 'certbot-dns-cloudflare.tex', u'certbot-dns-cloudflare Documentation',
147 | u'Certbot Project', 'manual'),
148 | ]
149 |
150 |
151 | # -- Options for manual page output ---------------------------------------
152 |
153 | # One entry per manual page. List of tuples
154 | # (source start file, name, description, authors, manual section).
155 | man_pages = [
156 | (master_doc, 'certbot-dns-cloudflare', u'certbot-dns-cloudflare Documentation',
157 | [author], 1)
158 | ]
159 |
160 |
161 | # -- Options for Texinfo output -------------------------------------------
162 |
163 | # Grouping the document tree into Texinfo files. List of tuples
164 | # (source start file, target name, title, author,
165 | # dir menu entry, description, category)
166 | texinfo_documents = [
167 | (master_doc, 'certbot-dns-cloudflare', u'certbot-dns-cloudflare Documentation',
168 | author, 'certbot-dns-cloudflare', 'One line description of project.',
169 | 'Miscellaneous'),
170 | ]
171 |
172 |
173 |
174 |
175 | # Example configuration for intersphinx: refer to the Python standard library.
176 | intersphinx_mapping = {
177 | 'python': ('https://docs.python.org/', None),
178 | 'acme': ('https://acme-python.readthedocs.org/en/latest/', None),
179 | 'certbot': ('https://certbot.eff.org/docs/', None),
180 | }
181 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. certbot-dns-cloudflare documentation master file, created by
2 | sphinx-quickstart on Tue May 9 10:20:04 2017.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to certbot-dns-cloudflare's documentation!
7 | ==================================================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 | :caption: Contents:
12 |
13 | .. automodule:: certbot_dns_cloudflare
14 | :members:
15 |
16 | .. toctree::
17 | :maxdepth: 1
18 |
19 | api
20 |
21 |
22 | Indices and tables
23 | ==================
24 |
25 | * :ref:`genindex`
26 | * :ref:`modindex`
27 | * :ref:`search`
28 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 | set SPHINXPROJ=certbot-dns-cloudflare
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
20 | echo.installed, then set the SPHINXBUILD environment variable to point
21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
22 | echo.may add the Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/local-oldest-requirements.txt:
--------------------------------------------------------------------------------
1 | acme[dev]==0.21.1
2 | certbot[dev]==0.21.1
3 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/readthedocs.org.requirements.txt:
--------------------------------------------------------------------------------
1 | # readthedocs.org gives no way to change the install command to "pip
2 | # install -e .[docs]" (that would in turn install documentation
3 | # dependencies), but it allows to specify a requirements.txt file at
4 | # https://readthedocs.org/dashboard/letsencrypt/advanced/ (c.f. #259)
5 |
6 | # Although ReadTheDocs certainly doesn't need to install the project
7 | # in --editable mode (-e), just "pip install .[docs]" does not work as
8 | # expected and "pip install -e .[docs]" must be used instead
9 |
10 | -e acme
11 | -e .
12 | -e certbot-dns-cloudflare[docs]
13 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
--------------------------------------------------------------------------------
/certbot/certbot-dns-burp/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | from setuptools import find_packages
3 |
4 |
5 | version = '0.31.0.dev0'
6 |
7 | # Remember to update local-oldest-requirements.txt when changing the minimum
8 | # acme/certbot version.
9 | install_requires = [
10 | 'acme>=0.21.1',
11 | 'certbot>=0.21.1',
12 | 'cloudflare>=1.5.1',
13 | 'mock',
14 | 'setuptools',
15 | 'zope.interface',
16 | ]
17 |
18 | docs_extras = [
19 | 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags
20 | 'sphinx_rtd_theme',
21 | ]
22 |
23 | setup(
24 | name='certbot-dns-cloudflare',
25 | version=version,
26 | description="Cloudflare DNS Authenticator plugin for Certbot",
27 | url='https://github.com/certbot/certbot',
28 | author="Certbot Project",
29 | author_email='client-dev@letsencrypt.org',
30 | license='Apache License 2.0',
31 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
32 | classifiers=[
33 | 'Development Status :: 3 - Alpha',
34 | 'Environment :: Plugins',
35 | 'Intended Audience :: System Administrators',
36 | 'License :: OSI Approved :: Apache Software License',
37 | 'Operating System :: POSIX :: Linux',
38 | 'Programming Language :: Python',
39 | 'Programming Language :: Python :: 2',
40 | 'Programming Language :: Python :: 2.7',
41 | 'Programming Language :: Python :: 3',
42 | 'Programming Language :: Python :: 3.4',
43 | 'Programming Language :: Python :: 3.5',
44 | 'Programming Language :: Python :: 3.6',
45 | 'Programming Language :: Python :: 3.7',
46 | 'Topic :: Internet :: WWW/HTTP',
47 | 'Topic :: Security',
48 | 'Topic :: System :: Installation/Setup',
49 | 'Topic :: System :: Networking',
50 | 'Topic :: System :: Systems Administration',
51 | 'Topic :: Utilities',
52 | ],
53 |
54 | packages=find_packages(),
55 | include_package_data=True,
56 | install_requires=install_requires,
57 | extras_require={
58 | 'docs': docs_extras,
59 | },
60 | entry_points={
61 | 'certbot.plugins': [
62 | 'dns-cloudflare = certbot_dns_cloudflare.dns_cloudflare:Authenticator',
63 | ],
64 | },
65 | test_suite='certbot_dns_cloudflare',
66 | )
67 |
--------------------------------------------------------------------------------
/certbot/certificaterenewal.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Renew certificates every X days
4 | #
5 | # requires openssl and bc
6 | #
7 |
8 | RENEWDAYS=30
9 |
10 | BASEDIR=__BASEDIR__
11 |
12 |
13 | DOMAIN=__DOMAIN__
14 |
15 | CURRENT=`/bin/date +%s`
16 | CERTIFICATE=`/usr/bin/openssl x509 -noout -dates -in $BASEDIR/certbot/letsencrypt/live/$DOMAIN/cert.pem | /bin/grep notAfter | /usr/bin/cut -d "=" -f 2`
17 | CERTDATE=`/bin/date -d "$CERTIFICATE" +%s`
18 |
19 | DAYS=`/bin/echo \($CERTDATE - $CURRENT\)/60/60/24 | /usr/bin/bc`
20 |
21 | if [ $DAYS -lt $RENEWDAYS ]; then
22 |
23 | echo Renewing certificate...
24 | # this may fail, we don't care
25 | docker stop burp
26 | docker rm burp
27 | cd $BASEDIR && \
28 | ./certbot/renew.sh $DOMAIN && \
29 | /bin/cp -r -f $BASEDIR/certbot/letsencrypt/live/$DOMAIN/ $BASEDIR/burp/keys && \
30 | chown 999:999 $PWD/burp/keys/$DOMAIN/privkey.pem && \
31 | ./burp/run.sh && \
32 | echo Certificate renewed
33 |
34 | else
35 |
36 | echo Still $DAYS days to expire. Not renewing
37 |
38 | fi
39 |
40 | echo waiting for 5 seconds just to make sure all is ok!
41 |
42 | sleep 5
43 |
44 | if [ ! "$(docker ps -q -f name=burp)" ]; then
45 | if [ "$(docker ps -aq -f status=exited -f name=burp)" ]; then
46 | # cleanup
47 | docker rm burp
48 | fi
49 | # run your container
50 | #docker run -d --name my-docker-image
51 | $BASEDIR/burp/run.sh
52 | echo burp docker has been restarted
53 | else
54 |
55 | echo burp docker is running
56 |
57 | fi
58 |
--------------------------------------------------------------------------------
/certbot/letsencrypt/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devoteam-cybertrust/burpcollaborator-docker/385e70115dc5eb43e78c7d7e99bd8fed7f8119d2/certbot/letsencrypt/.gitkeep
--------------------------------------------------------------------------------
/certbot/logs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devoteam-cybertrust/burpcollaborator-docker/385e70115dc5eb43e78c7d7e99bd8fed7f8119d2/certbot/logs/.gitkeep
--------------------------------------------------------------------------------
/certbot/new.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ $# -ne 1 ]; then
4 | echo usage: ./$0 \
5 | exit 0
6 | fi
7 |
8 | DOMAIN=$1
9 |
10 | echo Running certbot for domain $DOMAIN
11 | echo
12 | read -p "Press any key to continue, or CTRL-C to bail out" var_p
13 |
14 | docker run --rm --name certbot --hostname certbot -ti -p 53:53/udp -p 53:53 -v $PWD/certbot/logs:/var/log/letsencrypt -v $PWD/certbot/letsencrypt:/etc/letsencrypt/ certbot-burp certonly -d $DOMAIN -d *.$DOMAIN --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --no-eff-email --dns-cloudflare --register-unsafely-without-email --preferred-challenges dns-01
15 |
--------------------------------------------------------------------------------
/certbot/renew.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ $# -ne 1 ]; then
4 | echo usage: ./$0 \
5 | exit 0
6 | fi
7 |
8 | DOMAIN=$1
9 |
10 | echo Running certbot for domain $DOMAIN
11 |
12 | docker run --rm --name certbot --hostname certbot -ti -p 53:53/udp -p 53:53 -v $PWD/certbot/logs:/var/log/letsencrypt -v $PWD/certbot/letsencrypt:/etc/letsencrypt/ certbot-burp renew --force-renewal
13 |
--------------------------------------------------------------------------------
/init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | # Check if a file exists
6 | check_file() {
7 | if [ "$1" == "burp.jar" ]; then
8 | local file_path="./burp/pkg/$1"
9 | else
10 | local file_path="$1"
11 | fi
12 |
13 | if [ ! -e "$file_path" ]; then
14 | echo "ERROR: $file_path not found. Make sure it is in the correct location."
15 | exit 0
16 | fi
17 | }
18 |
19 | # Check if a command exists
20 | check_command() {
21 | which "$1" > /dev/null 2>&1
22 | if [ $? -eq 1 ]; then
23 | echo "ERROR: $1 is missing. Please install first."
24 | exit 0
25 | fi
26 | }
27 |
28 | handle_docker_permission_error() {
29 | echo "ERROR: Permission denied while trying to connect to the Docker daemon. Your user likely needs to use 'sudo' with docker, but we can add your user to the docker group and it should fix this."
30 | read -p "Would you like to add your user to the Docker group to fix this? (y/n): " choice
31 | if [ "$choice" == "y" ]; then
32 | sudo usermod -aG docker $USER
33 | echo "User added to the Docker group. Please log out and back in for the changes to take effect, then try the init script again."
34 | else
35 | echo "Exiting script. Please fix the Docker permissions manually."
36 | fi
37 | exit 1
38 | }
39 |
40 | if [ -e ./init.sh_has_been_run ]; then
41 | echo "Script has already been run. Bailing out."
42 | exit 0
43 | fi
44 |
45 | check_file "burp.jar"
46 | check_command "docker"
47 | check_command "bc"
48 | check_command "openssl"
49 |
50 | if [ $# -ne 2 ]; then
51 | echo "Usage: ./init.sh "
52 | exit 0
53 | fi
54 |
55 | DOMAIN=$1
56 | IP=$2
57 | METRICS=$(LC_CTYPE=C tr -dc A-Za-z0-9 < /dev/urandom | fold -w 10 | head -1)
58 |
59 | echo "Initialization to be done with domain *.$1 and public IP $2"
60 | read -p "Press any key to continue, or CTRL-C to bail out" var_p
61 |
62 | {
63 | # check if docker works
64 | docker container ls || handle_docker_permission_error
65 |
66 | # build the containers
67 | docker build -t certbot-burp certbot/certbot-dns-burp
68 | docker build -t burp burp
69 |
70 | # Get certs for the first time. The certbot container will be removed automatically afterwards.
71 | ./certbot/new.sh $DOMAIN
72 |
73 | # The symlinks from certbot will be wrong.
74 | # Copy the actual certificate files from the archive directory to burp/keys
75 | sudo cp ./certbot/letsencrypt/archive/$DOMAIN/cert1.pem ./burp/keys/cert.pem
76 | sudo cp ./certbot/letsencrypt/archive/$DOMAIN/chain1.pem ./burp/keys/chain.pem
77 | sudo cp ./certbot/letsencrypt/archive/$DOMAIN/fullchain1.pem ./burp/keys/fullchain.pem
78 | sudo cp ./certbot/letsencrypt/archive/$DOMAIN/privkey1.pem ./burp/keys/privkey.pem
79 |
80 | # Change ownership of the privkey.pem file to UID 999 and GID 999
81 | sudo chown 999:999 ./burp/keys/privkey.pem
82 |
83 | # Replace placeholders in burp config
84 | sudo /bin/sed -i "s/DOMAIN/$DOMAIN/g" ./burp/conf/burp.config
85 | sudo /bin/sed -i "s/IP/$IP/g" ./burp/conf/burp.config
86 | sudo /bin/sed -i "s/jnaicmez8/$METRICS/g" ./burp/conf/burp.config
87 |
88 | # run the burp container
89 | ./burp/run.sh
90 | sudo /bin/mv ./init.sh ./init.sh_has_been_run
91 | sudo /bin/chmod 000 ./init.sh_has_been_run
92 |
93 | # replace placeholders in renewal script
94 | sudo /bin/sed -i "s/__DOMAIN__/$DOMAIN/g" ./certbot/certificaterenewal.sh
95 | sudo /bin/sed -i "s#__BASEDIR__#$PWD#g" ./certbot/certificaterenewal.sh
96 | } || {
97 | echo "An error occurred during the execution of the script. Please check the output for details."
98 | exit 1
99 | }
100 |
101 | echo
102 | echo "SUCCESS! Burp is now running with the letsencrypt certificate for domain *.$DOMAIN"
103 | echo
104 | echo "Your metrics path was set to $METRICS. Change addressWhitelist to access it remotely."
105 | echo "Initialization script has completed."
106 |
--------------------------------------------------------------------------------