Files
vault-para/100-project/Work/Nacos with Self Signed Certificate.md
T

508 lines
14 KiB
Markdown
Raw Normal View History

2025-12-29 13:38:39 +08:00
Certainly! I can guide you through the process of using **cfssl** (Cloudflare's PKI toolkit) to generate a self-signed Certificate Authority (CA) and server certificate for your Nacos server. Then, I'll show you how to import the CA certificate into your Spring Boot application's Docker container so that it trusts the Nacos server's certificate.
This approach provides a robust and manageable way to handle certificates, especially when dealing with multiple services and environments.
---
## **Overview**
1. **Install cfssl and cfssljson**: Set up the cfssl toolkit.
2. **Generate a Self-Signed CA Certificate**: Create a root CA using cfssl.
3. **Generate a Server Certificate for Nacos Signed by the CA**: Create a certificate for your Nacos server.
4. **Configure the Nacos Server to Use the Server Certificate**: Set up Nacos to use the generated certificate.
5. **Import the CA Certificate into Your Spring Boot Application's Docker Container**: Ensure your application trusts the Nacos server's certificate.
6. **Configure Your Spring Boot Application**: Update settings to communicate with the Nacos server over HTTPS.
7. **Test the Setup**: Verify that everything works as expected.
---
## **Prerequisites**
- **cfssl and cfssljson** installed on your system.
- **Nacos server** installed and running.
- **Docker** installed and configured.
- **Spring Boot application** ready to be containerized.
---
## **Step 1: Install cfssl and cfssljson**
First, you need to install **cfssl** and **cfssljson**. These are command-line tools provided by Cloudflare for managing PKI.
### **1.1. Download the Binaries**
#### **For Linux:**
```bash
# Download cfssl
curl -L -o cfssl https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_linux-amd64
# Download cfssljson
curl -L -o cfssljson https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssljson_linux-amd64
```
#### **For macOS:**
```bash
# Download cfssl
curl -L -o cfssl https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_darwin-amd64
# Download cfssljson
curl -L -o cfssljson https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssljson_darwin-amd64
```
### **1.2. Make the Binaries Executable**
```bash
chmod +x cfssl cfssljson
```
### **1.3. Move the Binaries to Your PATH**
```bash
sudo mv cfssl cfssljson /usr/local/bin/
```
Alternatively, you can add the directory containing `cfssl` and `cfssljson` to your `PATH`.
### **1.4. Verify Installation**
```bash
cfssl version
cfssljson -version
```
---
## **Step 2: Generate a Self-Signed CA Certificate**
We'll create a self-signed CA certificate using cfssl.
### **2.1. Create a CA Configuration File (`ca-config.json`)**
Create a file named `ca-config.json` with the following content:
```json
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"nacos": {
"expiry": "87600h",
"usages": ["signing", "key encipherment", "server auth", "client auth"]
}
}
}
}
```
### **2.2. Create a CA Certificate Signing Request (`ca-csr.json`)**
Create a file named `ca-csr.json` with the following content:
```json
{
"CN": "My Root CA",
"key": {
"algo": "rsa",
"size": 4096
},
"names": [
{
"C": "US",
"ST": "State",
"L": "City",
"O": "YourOrganization",
"OU": "YourUnit"
}
]
}
```
### **2.3. Generate the CA Certificate and Key**
Run the following command:
```bash
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
```
This command generates:
- `ca.pem`: The CA certificate.
- `ca-key.pem`: The CA private key.
- `ca.csr`: The CA certificate signing request (not needed further).
**Note:** Keep `ca-key.pem` secure and do not share it.
---
## **Step 3: Generate a Server Certificate for Nacos Signed by the CA**
### **3.1. Create a Server Certificate Signing Request (`nacos-csr.json`)**
Create a file named `nacos-csr.json` with the following content:
```json
{
"CN": "nacos.example.com",
"hosts": [
"nacos.example.com",
"127.0.0.1",
"192.168.1.100"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"ST": "State",
"L": "City",
"O": "YourOrganization",
"OU": "YourUnit"
}
]
}
```
- **`CN`**: Common Name. Should match the domain name used to access Nacos.
- **`hosts`**: Include all DNS names and IP addresses that will be used to access the Nacos server.
- Replace `"nacos.example.com"` and `"192.168.1.100"` with your server's actual domain and IP address.
### **3.2. Generate the Server Certificate and Key**
Run the following command:
```bash
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=nacos nacos-csr.json | cfssljson -bare nacos
```
This command generates:
- `nacos.pem`: The Nacos server certificate.
- `nacos-key.pem`: The Nacos server private key.
- `nacos.csr`: The Nacos server CSR (not needed further).
### **3.3. Verify the Certificates**
You can inspect the server certificate:
```bash
openssl x509 -in nacos.pem -text -noout
```
---
## **Step 4: Configure the Nacos Server to Use the Server Certificate**
Now, configure your Nacos server to use the generated `nacos.pem` and `nacos-key.pem` files.
### **4.1. Convert the Certificates to PKCS#12 Format (If Necessary)**
Some servers require certificates in PKCS#12 format.
```bash
openssl pkcs12 -export -in nacos.pem -inkey nacos-key.pem -out nacos.p12 -name nacos -CAfile ca.pem -caname root -password pass:yourpassword
```
- **`nacos.p12`**: The PKCS#12 keystore file.
- **`yourpassword`**: Replace with a secure password.
### **4.2. Configure Nacos to Use SSL**
#### **Option A: Standalone Nacos (Embedded Tomcat)**
If you're running Nacos in standalone mode using embedded Tomcat, you can configure SSL in `application.properties` or `application.yml`.
**In `application.properties`:**
```properties
server.port=8848
server.ssl.enabled=true
server.ssl.key-store=classpath:nacos.p12
server.ssl.key-store-password=yourpassword
server.ssl.key-store-type=PKCS12
```
- **Note**: Place `nacos.p12` in the `classpath` (e.g., in the `resources` directory).
#### **Option B: Nacos with External Tomcat or Nginx**
If you're using an external server (like Tomcat or Nginx), configure it to use `nacos.pem` and `nacos-key.pem`.
**Example with Nginx:**
```nginx
server {
listen 443 ssl;
server_name nacos.example.com;
ssl_certificate /path/to/nacos.pem;
ssl_certificate_key /path/to/nacos-key.pem;
ssl_client_certificate /path/to/ca.pem;
ssl_verify_client off; # Change to 'on' if you want to verify client certificates
location / {
proxy_pass http://localhost:8848;
}
}
```
### **4.3. Restart the Nacos Server**
After configuring SSL, restart your Nacos server to apply the changes.
---
## **Step 5: Import the CA Certificate into Your Spring Boot Application's Docker Container**
Your Spring Boot application needs to trust the CA that signed the Nacos server's certificate. We'll import `ca.pem` into the Java trust store inside your Docker container.
### **5.1. Convert the CA Certificate to DER Format**
Java `keytool` requires certificates in DER format.
```bash
openssl x509 -outform der -in ca.pem -out ca.der
```
### **5.2. Update Your Dockerfile**
Modify your `Dockerfile` to include the CA certificate and import it into the Java trust store.
#### **Example Dockerfile:**
```dockerfile
# Use an official OpenJDK runtime as a parent image
FROM openjdk:17-jdk-slim
# Set the working directory
WORKDIR /app
# Copy the application's JAR file into the container
COPY target/your-application.jar /app/your-application.jar
# Copy the CA certificate into the container
COPY ca.der /tmp/ca.der
# Import the CA certificate into Java's trust store
RUN keytool -importcert \
-alias myca \
-keystore $JAVA_HOME/lib/security/cacerts \
-file /tmp/ca.der \
-storepass changeit \
-noprompt
# Clean up the temporary certificate file
RUN rm /tmp/ca.der
# Expose the application port
EXPOSE 8080
# Run the application
ENTRYPOINT ["java", "-jar", "/app/your-application.jar"]
```
**Notes:**
- **`COPY ca.der /tmp/ca.der`**: Ensure `ca.der` is in the same directory as your `Dockerfile`.
- **`$JAVA_HOME/lib/security/cacerts`**: Default Java trust store.
- **`-storepass changeit`**: Default password for `cacerts`. Use the correct password if it's different.
### **5.3. Build the Docker Image**
```bash
docker build -t your-application-image .
```
### **5.4. Run the Docker Container**
```bash
docker run -p 8080:8080 your-application-image
```
---
## **Step 6: Configure Your Spring Boot Application**
Ensure your application is configured to communicate with the Nacos server over HTTPS.
### **6.1. Update Application Properties**
In your `application.properties` or `application.yml`, update the Nacos server address to use `https` and the correct port.
**Example (`application.properties`):**
```properties
spring.cloud.nacos.server-addr=https://nacos.example.com:8848
spring.cloud.nacos.username=your-username
spring.cloud.nacos.password=your-password
```
### **6.2. Disable Hostname Verification (If Necessary)**
If the hostname verification fails, you may need to disable it (not recommended for production).
Add the following JVM option:
```bash
-Dcom.sun.net.ssl.checkRevocation=false -Djavax.net.ssl.trustStore=$JAVA_HOME/lib/security/cacerts
```
Alternatively, set up a custom `HostnameVerifier` in your code.
---
## **Step 7: Test the Setup**
After starting your Docker container, test your application to ensure it communicates securely with the Nacos server.
- **Check Logs**: Look for any SSL-related errors.
- **Verify Communication**: Ensure your application can register with Nacos or retrieve configurations.
---
## **Additional Considerations**
### **Using a Custom Trust Store**
Instead of modifying the default Java trust store (`cacerts`), you can create and use a custom trust store.
#### **5.2.1. Create a Custom Trust Store**
```dockerfile
# Create a custom trust store and import the CA certificate
RUN keytool -importcert \
-alias myca \
-keystore /app/truststore.jks \
-file /tmp/ca.der \
-storepass yourtruststorepassword \
-noprompt
```
#### **5.2.2. Set JVM Options to Use the Custom Trust Store**
```dockerfile
# Set environment variable for JVM options
ENV JAVA_OPTS="-Djavax.net.ssl.trustStore=/app/truststore.jks -Djavax.net.ssl.trustStorePassword=yourtruststorepassword"
```
#### **5.2.3. Update the ENTRYPOINT**
```dockerfile
ENTRYPOINT ["java", "$JAVA_OPTS", "-jar", "/app/your-application.jar"]
```
### **Handling Sensitive Information**
Avoid hardcoding passwords in your `Dockerfile`. Use build arguments or environment variables.
#### **Using Build Arguments**
```dockerfile
# Build argument for trust store password
ARG TRUSTSTORE_PASS=yourtruststorepassword
# Use the build argument in the RUN command
RUN keytool -importcert \
-alias myca \
-keystore /app/truststore.jks \
-file /tmp/ca.der \
-storepass $TRUSTSTORE_PASS \
-noprompt
# Set JVM options
ENV JAVA_OPTS="-Djavax.net.ssl.trustStore=/app/truststore.jks -Djavax.net.ssl.trustStorePassword=$TRUSTSTORE_PASS"
```
Build the Docker image with:
```bash
docker build --build-arg TRUSTSTORE_PASS=yourtruststorepassword -t your-application-image .
```
### **Securing Private Keys**
- **Do Not Include Private Keys in Docker Images**: Ensure that `ca-key.pem` and `nacos-key.pem` are not copied into the Docker image.
- **Secure Storage**: Store private keys securely and avoid committing them to version control.
---
## **Troubleshooting**
### **Common Issues and Solutions**
#### **SSLHandshakeException**
- **Cause**: The application doesn't trust the Nacos server's certificate.
- **Solution**: Ensure the CA certificate is correctly imported into the trust store.
#### **Hostname Verification Failure**
- **Cause**: The hostname used to access the Nacos server doesn't match the `CN` or `hosts` in the certificate.
- **Solution**:
- Ensure the Nacos server's domain matches the `CN` or is included in the `hosts` field.
- Use the correct domain or IP address when accessing the server.
- As a temporary measure, disable hostname verification (not recommended for production).
#### **Keytool Not Found**
- **Cause**: `keytool` is not available in the base Docker image.
- **Solution**: Use a JDK-based Docker image (e.g., `openjdk:17-jdk-slim`) instead of a JRE image.
#### **Incorrect Keystore Password**
- **Cause**: Wrong `storepass` used when importing the certificate.
- **Solution**: Verify the trust store password.
#### **Certificate Not Found**
- **Cause**: The certificate file is not correctly copied or the path is incorrect.
- **Solution**: Verify the `COPY` command and file paths in the `Dockerfile`.
### **Testing the Trust Store**
List the certificates in the trust store to confirm the import:
```dockerfile
RUN keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit
```
---
## **Summary**
By using **cfssl**, you've:
- Created a self-signed CA certificate.
- Generated a server certificate for your Nacos server signed by the CA.
- Configured your Nacos server to use the new SSL certificate.
- Imported the CA certificate into your Spring Boot application's Docker container, ensuring trust.
- Configured your application to communicate with the Nacos server over HTTPS.
This setup enhances security by establishing a trusted SSL connection between your application and the Nacos server.
---
## **Next Steps**
- **Automate Certificate Management**: Consider automating certificate renewal and distribution.
- **Use a Trusted CA in Production**: For production environments, obtain certificates from a trusted Certificate Authority.
- **Monitor SSL Connections**: Implement monitoring to detect and resolve SSL issues promptly.
---
## **References**
- [cfssl GitHub Repository](https://github.com/cloudflare/cfssl)
- [Nacos Documentation](https://nacos.io/en-us/docs/what-is-nacos.html)
- [Spring Boot SSL Configuration](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-configure-ssl)
---
Feel free to ask if you have any questions or need further assistance with any of the steps!