-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for cluster using http forward proxy #2481 #2777
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
|
||
HTTP Forward Proxy Support | ||
========================== | ||
|
||
It is possible to launch a kubernetes cluster from behind an http forward proxy ("corporate proxy"). To do so, you will need to configure the `egressProxy` for the cluster. | ||
|
||
It is assumed the proxy is already existing. If you want a private topology on AWS, for example, with an proxy instead of a NAT instance, you'll need to create the proxy yourself. See [Running in a shared VPC](run_in_existing_vpc.md). | ||
|
||
This configuration only manages proxy configurations for Kops and the Kubernetes cluster. We can not handle proxy configuration for application containers and pods. | ||
|
||
## Configuration | ||
|
||
Add `spec.egressProxy` port and url as follows | ||
|
||
``` yaml | ||
spec: | ||
egressProxy: | ||
httpProxy: | ||
host: proxy.corp.local | ||
port: 3128 | ||
``` | ||
|
||
Currently we assume the same configuration for http and https traffic. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 easy to change later (add an httpsProxy field), great to call out the limitation explicitly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep! That was my intent. I opened an issue to track it (#3069) |
||
|
||
## Proxy Excludes | ||
|
||
Most clients will blindly try to use the proxy to make all calls, even to localhost and the local subnet, unless configured otherwise. Some basic exclusions necessary for successful launch and operation are added for you at initial cluster creation. If you wish to add additional exclusions, add or edit `egressProxy.excludes` with a comma separated list of hostnames. Matching is based on suffix, ie, `corp.local` will match `images.corp.local`, and `.corp.local` will match `corp.local` and `images.corp.local`, following typical `no_proxy` environment variable conventions. | ||
|
||
``` yaml | ||
spec: | ||
egressProxy: | ||
httpProxy: | ||
host: proxy.corp.local | ||
port: 3128 | ||
excludes: corp.local,internal.corp.com | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is only going to work for layer 7 proxies, and if we - for example - but a NAT gateway in here it would not work as expected. That said I think this is fine, it can be a validation error. YAGNI :-) |
||
``` | ||
|
||
## AWS VPC Endpoints and S3 access | ||
|
||
If you are hosting on AWS have configured VPC "Endpoints" for S3 or other services, you may want to add these to the `spec.egressProxy.excludes`. Keep in mind that the S3 bucket must be in the same region as the VPC for it to be accessible via the endpoint. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,14 @@ limitations under the License. | |
|
||
package model | ||
|
||
import "k8s.io/kops/upup/pkg/fi" | ||
import ( | ||
"strconv" | ||
|
||
"github.com/golang/glog" | ||
"k8s.io/client-go/pkg/api/v1" | ||
"k8s.io/kops/pkg/apis/kops" | ||
"k8s.io/kops/upup/pkg/fi" | ||
) | ||
|
||
// s is a helper that builds a *string from a string value | ||
func s(v string) *string { | ||
|
@@ -28,6 +35,33 @@ func i64(v int64) *int64 { | |
return fi.Int64(v) | ||
} | ||
|
||
func getProxyEnvVars(proxies *kops.EgressProxySpec) []v1.EnvVar { | ||
if proxies == nil { | ||
glog.V(8).Info("proxies is == nil, returning empty list") | ||
return []v1.EnvVar{} | ||
} | ||
|
||
if proxies.HTTPProxy.Host == "" { | ||
glog.Warning("EgressProxy set but no proxy host provided") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can also check this in validation, but no harm in calling it out here. If we know this is going to go wrong, should we skip setting the env vars? We could also return an error in this case... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. returning an error just forces the caller to deal with the situation right? I'm not 100% sure either way. Things are probably going to fail to come up in this situation, we defiantly want to catch this in validation in any case, but as to whether we should return an error here, since I'm not sure, I'm just going to lean towards YAGNI and leave it as is. |
||
} | ||
|
||
var httpProxyURL string | ||
if proxies.HTTPProxy.Port == 0 { | ||
httpProxyURL = "http://" + proxies.HTTPProxy.Host | ||
} else { | ||
httpProxyURL = "http://" + proxies.HTTPProxy.Host + ":" + strconv.Itoa(proxies.HTTPProxy.Port) | ||
} | ||
|
||
noProxy := proxies.ProxyExcludes | ||
|
||
return []v1.EnvVar{ | ||
{Name: "http_proxy", Value: httpProxyURL}, | ||
{Name: "https_proxy", Value: httpProxyURL}, | ||
{Name: "NO_PROXY", Value: noProxy}, | ||
{Name: "no_proxy", Value: noProxy}, | ||
} | ||
} | ||
|
||
// b returns a pointer to a boolean | ||
func b(v bool) *bool { | ||
return fi.Bool(v) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -276,6 +276,9 @@ func (t *ProtokubeBuilder) ProtokubeFlags(k8sVersion semver.Version) *ProtokubeF | |
func (t *ProtokubeBuilder) ProtokubeEnvironmentVariables() string { | ||
var buffer bytes.Buffer | ||
|
||
// TODO write out an environments file for this. This is getting a tad long. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 but no need to do as part of this PR. We also are being a bit cavalier with escaping, so building up a map[string]string of env and then carefully writing it would help there also! I think here we still need to pass |
||
|
||
// Pass in required credentials when using user-defined s3 endpoint | ||
if os.Getenv("AWS_REGION") != "" { | ||
buffer.WriteString(" ") | ||
buffer.WriteString("-e 'AWS_REGION=") | ||
|
@@ -284,7 +287,6 @@ func (t *ProtokubeBuilder) ProtokubeEnvironmentVariables() string { | |
buffer.WriteString(" ") | ||
} | ||
|
||
// Pass in required credentials when using user-defined s3 endpoint | ||
if os.Getenv("S3_ENDPOINT") != "" { | ||
buffer.WriteString(" ") | ||
buffer.WriteString("-e S3_ENDPOINT=") | ||
|
@@ -306,9 +308,21 @@ func (t *ProtokubeBuilder) ProtokubeEnvironmentVariables() string { | |
buffer.WriteString(" ") | ||
} | ||
|
||
t.writeProxyEnvVars(&buffer) | ||
|
||
return buffer.String() | ||
} | ||
|
||
func (t *ProtokubeBuilder) writeProxyEnvVars(buffer *bytes.Buffer) { | ||
for _, envVar := range getProxyEnvVars(t.Cluster.Spec.EgressProxy) { | ||
buffer.WriteString(" -e ") | ||
buffer.WriteString(envVar.Name) | ||
buffer.WriteString("=") | ||
buffer.WriteString(envVar.Value) | ||
buffer.WriteString(" ") | ||
} | ||
} | ||
|
||
// buildCertificateTask is responsible for build a certificate request task | ||
func (t *ProtokubeBuilder) buildCeritificateTask(c *fi.ModelBuilderContext, name, filename string) error { | ||
cert, err := t.KeyStore.Cert(name) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do have
egress
which is where we configure a natGateway. Currently that is defined on the subnet level, because of the limitations of NAT subnets. We should consider whether this is the same thing, and whether we want to expand egress to cover this. My knee-jerk is yes...(In practice, we only have to preserve serialized API compatibility, so this means renaming the field. We can harmonize the two fields later.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the flip-side, I guess the argument is that we could have both egress and egressProxy. i.e. we want to use an HTTP proxy, but we also want to tunnel through a VPN / gateway.
I'm not the expert here - if http proxy & gateway are both possible, then this makes sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think conceivably the http proxy would be in addition to one or more of these other options.