|
|
Line 4: |
Line 4: |
| | | |
| == Setting up a public key infrastructure == | | == Setting up a public key infrastructure == |
| + | |
| + | {{Main|Create a OpenVPN Certificate Authority}} |
| | | |
| The use of client certificates enhances the security, but makes it harder to deploy, as you need to distribute client certificates to each host. You '''can not use an existing public key infrastructure''' (PKI); you would allow anyone with a certificate of that PKI to connect to your server (the <code>tls-remote</code> and <code>tls-verify</code> options can limits the allowed clients). You either need to to set up your own certificate infrastructure, or limit OpenVPN to use password-based authentication (see the options <code>auth-user-pass-verify</code>, <code>client-cert-not-required</code> and <code>username-as-common-name</code>). | | The use of client certificates enhances the security, but makes it harder to deploy, as you need to distribute client certificates to each host. You '''can not use an existing public key infrastructure''' (PKI); you would allow anyone with a certificate of that PKI to connect to your server (the <code>tls-remote</code> and <code>tls-verify</code> options can limits the allowed clients). You either need to to set up your own certificate infrastructure, or limit OpenVPN to use password-based authentication (see the options <code>auth-user-pass-verify</code>, <code>client-cert-not-required</code> and <code>username-as-common-name</code>). |
Line 9: |
Line 11: |
| The easiest method it to use easy-rsa, as described in the [http://openvpn.net/index.php/open-source/documentation/howto.html OpenVPN How-to]. | | The easiest method it to use easy-rsa, as described in the [http://openvpn.net/index.php/open-source/documentation/howto.html OpenVPN How-to]. |
| | | |
− | This article describes the steps taken by easy-rsa in more detail, but basically gives the same result. This article is partly based on the excellent tutorial by [http://www.phildev.net/ Phil Dibowitz] on [http://www.phildev.net/ssl/creating_ca.html creating an CA].
| + | The article [[Create a OpenVPN Certificate Authority]] describes the steps in more detail, but basically gives the same result. |
| | | |
| Certificates, when deployed correctly, are ''much'' more secure than passwords, since the secret (key) does not need to be exchanged or shared between the different hosts. However, doing so requires a security hygiene which may not be required for a small-scale deployment. | | Certificates, when deployed correctly, are ''much'' more secure than passwords, since the secret (key) does not need to be exchanged or shared between the different hosts. However, doing so requires a security hygiene which may not be required for a small-scale deployment. |
− |
| |
− | === Files ===
| |
− |
| |
− | The following files are used by OpenSSL:
| |
− |
| |
− | {|
| |
− | ! Filename !! Needed by !! Purpose !! Secret
| |
− | |-
| |
− | | ca.cnf || CA || CA configuration of its common name (CN) || No
| |
− | |-
| |
− | | ca-sign.cnf || CA || CA configuration for Signing || No
| |
− | |-
| |
− | | ca.key || CA || Root CA key || Yes
| |
− | |-
| |
− | | ca.crt || CA + server + all clients || Root CA certificate || No
| |
− | |-
| |
− | | index.txt || CA || List of all signed certificates || No
| |
− | |-
| |
− | | serial || CA || First free serial number of certificates || No
| |
− | |-
| |
− | | crl.pem || CA + server (+ all clients) || Certificate revokation list || No
| |
− | |-
| |
− | | crlnumber || CA || First free serial number of CRLs || No
| |
− | |-
| |
− | | .rand || CA || Root CA certificate || Yes?
| |
− | |-
| |
− | | dh2048.pem || server only || Diffie Hellman parameters || No
| |
− | |-
| |
− | | server.cnf || server only during certificate generation || Server configuration || No
| |
− | |-
| |
− | | client1.req || CA only during certificate generation || Client1 certificate signing request || No
| |
− | |-
| |
− | | server.key || server only || Server key || Yes
| |
− | |-
| |
− | | server.crt || server only || Server certificate || No
| |
− | |-
| |
− | | client1.cnf || client 1 only during certificate generation || Client 1 configuration || No
| |
− | |-
| |
− | | client1.req || CA only during certificate generation || Client1 certificate signing request || No
| |
− | |-
| |
− | | client1.key || client 1 only || Client1 key || Yes
| |
− | |-
| |
− | | client1.crt || client 1 only || Client1 certificate || No
| |
− | |-
| |
− | | client2.cnf || client 2 only during certificate generation || Client 2 configuration || No
| |
− | |-
| |
− | | client2.req || CA only during certificate generation || Client2 certificate signing request || No
| |
− | |-
| |
− | | client2.key || client 2 only || Client2 key || Yes
| |
− | |-
| |
− | | client2.crt || client 2 only || Client2 certificate || No
| |
− | |}
| |
− |
| |
− | I'll use these directories to denote the files that are required on different host:
| |
− |
| |
− | {|
| |
− | ! Directory !! Needed by
| |
− | |-
| |
− | | ca || CA
| |
− | |-
| |
− | | server || server
| |
− | |-
| |
− | | client1 || client 1
| |
− | |-
| |
− | | client2 || client 2
| |
− | |}
| |
− |
| |
− | This is a compromise between the completely flat file structure of easy-rsa, and the recommendations set forth by most CA tutorials, which creates directories for certificate requests (<code>.req</code>), signed certificates (<code>.crt</code>), certificate revokations (<code>crl</code>), and private keys (<code>ca.key</code>).
| |
− |
| |
− | If you are serious about security, you should not run these commands on the same machine, but run commands in the server, client1, and client2 directory of respectively the server and client machines, and run commands in the CA directory on a machine that is not connected to the Internet.
| |
− |
| |
− | === Initialize ===
| |
− |
| |
− | (roughly equivalent to <code>easy-rsa/clean-all</code>)
| |
− |
| |
− | mkdir ca server client1 client2
| |
− | cd ca
| |
− | touch index.txt
| |
− |
| |
− | === CA Configuration Files ===
| |
− |
| |
− | Create configuration files. In our setup, <code>ca-sign.cnf</code> contains the configuration for signing certificates. We only use it in conjunction with the <code>openssl ca</code> command. It described the folder structure within the ca directory, the location of support files for the CA, as well as properties of the signed certificates (duration, restricted usage) as well as the policy for the name ("distinguished name") of signed certificates. Finally, it lists the policy for certification revocation lists.
| |
− |
| |
− | # ca-sign.cnf
| |
− | # This configuration file is used by the 'ca' command, to create signed certificates.
| |
− | [ ca ]
| |
− | default_ca = CA_default # The default ca section
| |
− |
| |
− | [ CA_default ]
| |
− | dir = /path/to/ca # Where everything is kept
| |
− | certs = $dir/ # Where the issued certs are kept
| |
− | crl_dir = $dir/ # Where the issued crl are kept
| |
− | new_certs_dir = $dir/ # default place for new certs
| |
− |
| |
− | private_key = $dir/ca.key # The private key
| |
− | certificate = $dir/ca.crt # The CA root certificate
| |
− | database = $dir/index.txt # List of signed certificates
| |
− | serial = $dir/serial # The current serial number
| |
− | crlnumber = $dir/crlnumber # the current crl number
| |
− | crl = $dir/crl.pem # The current CRL
| |
− | RANDFILE = $dir/.rand # private random number file
| |
− |
| |
− | unique_subject = no # allow multiple certificates with same subject.
| |
− | default_md = default # Use hash algorithm specified in the request
| |
− | default_days = 3650 # client certificates last 10 years
| |
− | #default_crl_days = 30 # How often clients should download the CRL
| |
− |
| |
− | #x509_extensions = X509_ca # The x509 extensions for the root certificate
| |
− | #x509_extensions = X509_server # The x509 extensions for a server certificate
| |
− | x509_extensions = X509_client # The x509 extensions for a client certificate
| |
− |
| |
− | # These options control what fields from the distinguished name to show before signing.
| |
− | # They are required to make sure all fields are shown.
| |
− | name_opt = ca_default # Subject Name options
| |
− | cert_opt = ca_default # Certificate field options
| |
− |
| |
− | copy_extensions = copy # Copy extensions, such as subjectAltName, from the request
| |
− |
| |
− | policy = policy_dn
| |
− |
| |
− | [ X509_ca ]
| |
− | # X509v3 extensions for the root certificate
| |
− | basicConstraints = CA:TRUE
| |
− | subjectKeyIdentifier = hash
| |
− | authorityKeyIdentifier = keyid:always,issuer:always
| |
− | #subjectAltName = email:move # Move the email address from the DN in the request to here
| |
− | #crlDistributionPoints = URI:http://www.example.com/example_ca.crl
| |
− |
| |
− | [ X509_server ]
| |
− | # X509v3 extensions for server certificates
| |
− | basicConstraints = CA:FALSE
| |
− | nsCertType = server
| |
− | subjectKeyIdentifier = hash
| |
− | authorityKeyIdentifier = keyid,issuer
| |
− | #subjectAltName = email:move # Move the email address from the DN in the request to here
| |
− | #crlDistributionPoints = URI:http://www.example.com/example_ca.crl
| |
− |
| |
− | [ X509_client ]
| |
− | # X509v3 extensions for client certificates
| |
− | basicConstraints = CA:FALSE
| |
− | nsCertType = client
| |
− | subjectKeyIdentifier = hash
| |
− | authorityKeyIdentifier = keyid,issuer
| |
− | #subjectAltName = email:move # Move the email address from the DN in the request to here
| |
− | #crlDistributionPoints = URI:http://www.example.com/example_ca.crl
| |
− |
| |
− | [ policy_dn ]
| |
− | countryName = supplied # required parameter, any value allowed
| |
− | stateOrProvinceName = optional
| |
− | localityName = optional
| |
− | organizationName = match # required, and must match root certificate
| |
− | organizationalUnitName = optional
| |
− | commonName = supplied # required parameter, any value allowed
| |
− | emailAddress = optional # email address in DN is deprecated, use subjectAltName
| |
− |
| |
− | <code>ca.cnf</code> defines the distinguished name for the certificate authority. It also contains the key length (2048 is recommended nowadays, over the default of 1024), and if the key should be encrypted.
| |
− |
| |
− | # ca.cnf
| |
− | # This configuration file is used by the 'req' command when the root certificates is created.
| |
− | [ req ]
| |
− | default_bits = 2048 # default strength of client certificates
| |
− | default_md = sha1
| |
− | encrypt_key = yes # "no" is equivalent to -nodes
| |
− | prompt = no
| |
− | string_mask = utf8only
| |
− | distinguished_name = ca_distinguished_name # root certificate name
| |
− | req_extensions = req_cert_extensions
| |
− | # attributes = req_attributes
| |
− |
| |
− | [ ca_distinguished_name ]
| |
− | # root certificate name
| |
− | countryName = NL
| |
− | #stateOrProvinceName = Utrecht
| |
− | localityName = Hometown
| |
− | organizationName = My Organisation
| |
− | #organizationalUnitName = My Department Name
| |
− | commonName = OpenVPN-CA
| |
− | #emailAddress = hostmaster@example.org # email in DN is deprecated, use subjectAltName
| |
− |
| |
− | [ req_cert_extensions ]
| |
− | # nsCertType = server
| |
− | subjectAltName = email:hostmaster@example.org
| |
− |
| |
− | Traditionally, the email address was part of the distinguished name, like so:
| |
− | Subject: C=NL, O=MyOrganisation, CN="www.example.org", emailAddress=hostmaster@macfreek.nl
| |
− |
| |
− | However, RFC 3850 (section 3) specifies that nowadays:
| |
− | :The email address SHOULD be in the subjectAltName extension, and SHOULD NOT be in the subject distinguished name.
| |
− |
| |
− | Like so:
| |
− | Subject: C=NL, O=MyOrganisation, CN="www.example.org"
| |
− | X509v3 extensions:
| |
− | X509v3 Subject Alternative Name:
| |
− | email:hostmaster@macfreek.nl
| |
− |
| |
− | In the above request, the email is already specified in the request. The SubjectAltName (and all other extensions) are copied by this setting:
| |
− | copy_extensions = copy
| |
− |
| |
− | An alternative is to specify the email address in the distinguished name (DN) in the request, but copy or move it to the subjectAltName by one of these two settings:
| |
− | subjectAltName=email:copy
| |
− | subjectAltName=email:move
| |
− |
| |
− | === Build CA certificate ===
| |
− |
| |
− | (roughly equivalent to <code>easy-rsa/build-ca</code> or <code>pkitool --interact --initca</code>)
| |
− |
| |
− | If your CA should be valid after the year 2038, be sure to use openssl 0.9.9 or higher.
| |
− |
| |
− | First create a request with the correct name, and then self-sign a certificate and create a serial number file.
| |
− |
| |
− | cd ca
| |
− | openssl req -new -config ca.cnf -keyout ca.key -out ca.req
| |
− | openssl ca -config ca-sign.cnf -extensions X509_ca -days 21700 -create_serial -selfsign \
| |
− | -keyfile ca.key -in ca.req -out ca.crt
| |
− | chmod 400 ca.key
| |
− | chmod 444 ca.crt
| |
− |
| |
− | These actions create ca.key and ca.crt. ca.key should be kept secret. ca.crt should be distributed to all servers and clients.
| |
− |
| |
− | cp ca/ca.crt server/
| |
− | cp ca/ca.crt client1/
| |
− | cp ca/ca.crt client2/
| |
− |
| |
− | === Generate Prime Numbers ===
| |
− |
| |
− | (roughly equivalent to <code>build-dh</code>)
| |
− |
| |
− | cd server
| |
− | openssl dhparam -out dh2048.pem 2048
| |
− |
| |
− | === Build server certificate ===
| |
− |
| |
− | (roughly equivalent to <code>build-key-server myserver</code> or <code>pkitool --interact --server myserver</code>)
| |
− |
| |
− | First create a configuration for the server:
| |
− |
| |
− | # server.cnf
| |
− | # This configuration file is used by the 'req' command when the server certificate is created.
| |
− | [ req ]
| |
− | default_bits = 2048
| |
− | default_keyfile = server.key
| |
− | default_md = sha1
| |
− | encrypt_key = no
| |
− | prompt = no
| |
− | distinguished_name = server_distinguished_name
| |
− | req_extensions = req_cert_extensions
| |
− | # attributes = req_attributes
| |
− | x509_extensions = usr_cert
| |
− |
| |
− | [ server_distinguished_name ]
| |
− | countryName = NL
| |
− | #stateOrProvinceName = Utrecht
| |
− | localityName = Breukelen
| |
− | organizationName = MacFreek
| |
− | #organizationalUnitName = My Department Name
| |
− | commonName = gateway.macfreek.nl
| |
− | emailAddress = hostmaster@macfreek.nl
| |
− |
| |
− | [ req_cert_extensions ]
| |
− | nsCertType = server
| |
− |
| |
− | [ v3_ca ]
| |
− | subjectAltName = email:hostmaster@macfreek.nl
| |
− |
| |
− | Create the server request and private key:
| |
− | cd server
| |
− | openssl req -new -config server.cnf -keyout server.key -out server.req
| |
− | chmod 400 server.key
| |
− |
| |
− | Copy server.req to the CA machine, and run on the CA machine:
| |
− | cp server/server.req ca/
| |
− | cd ca
| |
− | openssl ca -config -extensions X509_server ca.cnf -in server.req -out server.crt
| |
− |
| |
− | Copy server.crt to the client machine.
| |
− | cp ca/server.crt server/
| |
− |
| |
− | You can delete server.req. Only server.crt and server.key are required on the server.
| |
− |
| |
− | If you have multiple servers, repeat this step for all servers.
| |
− |
| |
− | === Build client certificate ===
| |
− |
| |
− | (roughly equivalent to <code>pkitool --interact --csr myclient</code>)
| |
− |
| |
− | On the client machine
| |
− | openssl req -new -config client1.cnf -keyout client1.key -out client1.req
| |
− | chmod go-rw client1.key
| |
− |
| |
− | Copy client1.req to the CA machine, and run on the CA machine:
| |
− | openssl ca -config ca.cnf -out client1.crt -in client1.req
| |
− |
| |
− | Copy client1.crt to the client machine.
| |
− |
| |
− | You can delete client1.req. Only client1.crt and client1.key are required on the client.
| |
− |
| |
− | Repeat this step for all client hosts.
| |
− |
| |
− | === Revoke a client certificate ===
| |
− |
| |
− | if the file crlnumber does not exist:
| |
− | echo '0000000000000001' > crlnumber
| |
− |
| |
− | openssl ca -config ca.cnf -crl_reason superseded -revoke 5FE840894254A22.crt
| |
− | openssl ca -config ca.cnf -gencrl -out crl.pem
| |
− |
| |
− | where the reason is one of the following
| |
− | * unspecified
| |
− | * keyCompromise
| |
− | * CACompromise
| |
− | * affiliationChanged
| |
− | * superseded
| |
− | * cessationOfOperation
| |
− | * certificateHold
| |
− |
| |
− | Test if you receive an error (code 23):
| |
− |
| |
− | cat ca.crt crl.pem > revoke-test.pem
| |
− | openssl verify -CAfile revoke-test.pem -crl_check 5FE840894254A22.crt
| |
− |
| |
− | === Change password ===
| |
− |
| |
− | To change the password of your private key:
| |
− | openssl rsa -des3 -in ca.key -out ca_new.key
| |
− | mv ca_new.key ca.key
| |
OpenVPN is a secure tunnel. I use it to connect to my home network.
OpenVPN uses certificates to both authenticate the client with the server, and the server with the client. The only hard part about OpenVPN is setting up the certificate infrastructure. You need a root certificate (the certificate authority, CA), and certificates for each server and each client, signed by this root certificate.
The use of client certificates enhances the security, but makes it harder to deploy, as you need to distribute client certificates to each host. You can not use an existing public key infrastructure (PKI); you would allow anyone with a certificate of that PKI to connect to your server (the tls-remote
and tls-verify
options can limits the allowed clients). You either need to to set up your own certificate infrastructure, or limit OpenVPN to use password-based authentication (see the options auth-user-pass-verify
, client-cert-not-required
and username-as-common-name
).