This post is about a specific problem I encountered where I couldn't make any requests from my Docker container to the outside world. It was my first time working with Jenkins Pipelines and decided to use Docker as my isolation agent.
Some facts related to my environment:
- Jenkins is running on Tomcat, not on a Docker container
- I have port redirection (80 to 8080 and 443 to 8443) using iptables
Code in question
The relevant part of my Jenkinsfile is this:
stage('build and test apps') {
failFast true
parallel {
stage('front end') {
steps {
sh 'npm install --prefix front_end/'
sh 'npm run build --prefix front_end/'
sh 'npm run test --prefix front_end/'
}
}
stage('back end') {
steps {
sh 'npm install --prefix back_end/'
sh 'npm run test --prefix back_end/'
}
}
}
}
The logs
The requests needed on the npm install
command were failing with 403 http errors and this log was appearing:
npm ERR! Unexpected token < in JSON at position 0
npm ERR! <html><head><meta http-equiv='refresh' content='1;url=/login?from=%2Freact-scripts'/><script>window.location.replace('/login?from=%2Freact-scripts');</script></head><body style='background-color:white; color:white;'>
npm ERR!
npm ERR!
npm ERR! Authentication required
npm ERR! <!--
npm ERR! You are authenticated as: anonymous
npm ERR! Groups that you are in:
npm ERR!
npm ERR! Permission you need to have (but didn't): hudson.model.Hudson.Read
npm ERR! ... which is implied by: hudson.security.Permission.GenericRead
npm ERR! ... which is implied by: hudson.model.Hudson.Administer
npm ERR! -->
npm ERR!
npm ERR! </body></html>
npm ERR!
npm ERR! If you need help, you may report this error at:
npm ERR! <https://github.com/npm/npm/issues>
After reading the logs, the first thing I thought was: this is something related to permissions of the user running the Docker container- tomcat in my case -but they weren't.
After debugging for quite a while, I stumbled upon some divine light on StackOverflow. Thanks to this, I found that I was redirecting all port 80 and 443 trafic from everywhere to their corresponding 8080 and 8443 ports.
The solution
Alter the iptables to create a negated rule and avoid redirects from the Docker subnet.
First, check your current iptables with this command:
iptables -t nat -L -n --line-numbers
Chain PREROUTING (policy ACCEPT)
num target prot opt source destination
1 REDIRECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 8080
2 REDIRECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 redir ports 8443
3 tcp -- 0.0.0.0/0 0.0.0.0/0
4 DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
1 REDIRECT tcp -- 0.0.0.0/0 127.0.0.1 tcp dpt:443 redir ports 8443
2 REDIRECT tcp -- 0.0.0.0/0 127.0.0.1 tcp dpt:80 redir ports 8080
3 DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
num target prot opt source destination
1 MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
num target prot opt source destination
1 RETURN all -- 0.0.0.0/0 0.0.0.0/0
The value 0.0.0.0/0 on the source column refers to all trafic. So, in my case, I need to replace the first two entries of both the PREROUTING and OUTPUT chain:
Note: The default Docker subnet is 172.17.0.0/16. If you changed the default configurations make sure to change them in the commands also.
PREROUTING
iptables -t nat -R PREROUTING 1 ! -s 172.17.0.0/16 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -R PREROUTING 2 ! -s 172.17.0.0/16 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443
OUTPUT
iptables -t nat -R OUTPUT 1 ! -s 172.17.0.0/16 -d 127.0.0.1/32 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443
iptables -t nat -R OUTPUT 2 ! -s 172.17.0.0/16 -d 127.0.0.1/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
Now, requests from the Docker container return with a 200 http status and everyone is happy 🤗 Hope this helps you if you are having a similar problem!
As a side note, while doing all this, I also needed to learn more about iptables and their different options. I found this quick guide from linode handy.
Thanks for reading me!