Skip to content
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

CNAME flattening #3403

Merged
merged 23 commits into from
Jul 3, 2018
Merged

CNAME flattening #3403

merged 23 commits into from
Jul 3, 2018

Conversation

gamalan
Copy link
Contributor

@gamalan gamalan commented May 28, 2018

What does this PR do?

Allow handling host rule with different names than the HOST header that comes in.

Motivation

I am working in a project that allow user masking their domain/subdomain to our domain. Previously, only able to serve request that have same host rule and host header that came.

Fixes #141

More

Additional Notes

  • To allow generate/serving the request SSL, must use httpChallenge with active onDemand rule, dnsChallenge is only possible if the request host dns is also managed by ours own.
  • ACME onDemand config, should not be deprecated, if it being deprecated and removed, then this feature will lost the ability to generate the requested SSL cert. Resulting to a breaking response because SSL protocol error, Invalid CA/CN, etc.
  • Current additional config example
[hostResolver] #currently using resolver label
cnameFlattening = true #default is false, if this not set true, following config is useless
resolvConfig = "/etc/resolv.conf" # default is /etc/resolv.conf, if changed, the following file must follow resolv.conf standard
resolvDepth = 5 # maximum CNAME lookup depth before finishing

- Resolve CNAME recursively
- Get the first(request) and last(potential)
- Compare with the available host rule
- add cache mechanism for cname flattening
@ldez ldez changed the title CNAME flattening #141 CNAME flattening May 28, 2018
@nmengin
Copy link
Contributor

nmengin commented May 29, 2018

Hello @gamalan .

Many thanks for this PR. 👍

We talked about it with the team and, even if we understand the need, we are not sure that it's a best practice to check the CNAME flattening by default.
Indeed, only Cloudflare implements this (useful) feature and, I guess, only a part of Clouflare users use it.

That's why, I guess it should be great if the CNAME flattening was enable thanks to a flag. Thus only users who really need it will activate it.

WDYT?

@gregorybrzeski
Copy link

AFAIK Openstack Swift is using CNAME flattening, as a precaution they have a limit (lookup_depth) of dns resolves which are allowed for each request.

https://docs.openstack.org/newton/config-reference/object-storage/features.html

"CNAME lookup"

https://github.com/openstack/swift/blob/master/swift/common/middleware/cname_lookup.py

@gamalan
Copy link
Contributor Author

gamalan commented May 29, 2018

@nmengin agreed, not all people need this. My take is set up an additional set of global config, inside entrypoint, called entryPoints.resolver or a new set of config, simply called resolver. With a set of value for :

  1. CNAMEFlattening = true/false if false, any other option is useless, the default is false
  2. resolverDepth = 0-XX, how deep it should lookup a DNS record, 0 means unlimited. default is 0
  3. cache = 0-XX, cache time, in a minutes format, the default is 30 minutes.

An example :

[entryPoints.resolver]
CNAMEFlattening = true
resolverDepth = 10
cache = 30

NB : to able generating the SSL for the incoming request, this feature need onDemand rule to be available (currently is being deprecated)

Happy to accept some opinion.

@gregorybrzeski
Copy link

@gamalan if you set resolverDepth by default to 0 (unlimited), then what would happen if the CNAME resolve chain has a circular reference ? Maybe setting it by default to 3 or 5 would be a better option ?

Would you also consider a case where dns servers for CNAMEFlattening resolving can be specified in config file ? The /etc/resolv.conf can be pointing to internal dns servers which might not be (in some cases) best choice to use as a resolving dns servers for CNAMEFlattening process.

@ldez ldez added this to the 1.7 milestone May 30, 2018
@gamalan
Copy link
Contributor Author

gamalan commented May 30, 2018

@gregorybrzeski ah, forgot about that case, you are right, I think 5 should suffice for default. Also for the resolver config, good idea, but it should follow the resolv.conf standard(not sure gonna work in windows though).

@gamalan
Copy link
Contributor Author

gamalan commented May 30, 2018

Updated, already make a new set of config, haven't been pushed yet. Currently, the CNAME flattening process is separated as a new package, the unit test has been added, the integration test and documentation is WIP. Not sure where to put for the documentation.

The additional config is set to global, as example

[resolver] #currently using resolver label
cnameFlattening = true #default is false, if this not set true, following config is useless
resolvConfig = "/etc/resolv.conf" # default is /etc/resolv.conf, if changed, the following file must follow resolv.conf standard
resolvDepth = 5 # maximum CNAME lookup depth before finishing
cacheDuration = "30m" # default cache expiration 30 minute

@ldez ldez removed this from the 1.7 milestone May 30, 2018
@nmengin
Copy link
Contributor

nmengin commented May 30, 2018

Hello @gamalan ,

Many thanks for the modifications you made.

We think the resolver block is a good idea but we prefer keep the resolvdepth and the cacheduration hardcoded.

The flag should look like this :

[resolver] #currently using resolver label
cnameFlattening = true #default is false, if this not set true, following config is useless
resolvConfig = "/etc/resolv.conf" # default is /etc/resolv.conf, if changed, the following file must follow resolv.conf standard

Moreover, we would like to give the possibility to the users to enable resolver and customizeresolver.resolvconfig even if the resolver.cnameflattening is set to false.
It can be useful for others Use Cases.

WDYT?

Copy link
Contributor

@nmengin nmengin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @gamalan .

Few new remarks 😉


```

- To allow serving secure https request and generate the SSL using ACME while `cnameFlattening` is set to `true`. The `acme` configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please only write one sentence by line.

```

- To allow serving secure https request and generate the SSL using ACME while `cnameFlattening` is set to `true`. The `acme` configuration
for `HTTP-01` challenge and `onDemand` is mandatory. Refer to [ACME configuration](/configuration/acme) for more information.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please only write one sentence by line.

Record string
}

// CNAMEFlatten check if CNAME records is exists, flatten if possible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CNAMEFlatten check if CNAME records is exists,

Please modify in CNAMEFlatten check if CNAME records exists.

return result[0], result[len(result)-1]
}

// CNAMEResolve resolve CNAME if exists, and return with the highest TTL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you correct the comment please: CNAMEResolve resolves CNAME if exists, and returns with the highest TTL ?


// CNAMEResolve resolve CNAME if exists, and return with the highest TTL
func (hr *HostResolver) CNAMEResolve(host string) *CNAMEResolv {
config, _ := dns.ClientConfigFromFile(hr.ResolvConfig)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you manage the error please?

r, _, err := c.Exchange(m, net.JoinHostPort(config.Servers[i], config.Port))
if err != nil {
log.Errorf("Failed to resolve host %s with server %s", host, config.Servers[i])
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to contin ue to precces the statement in the loop if there is an error?
WDYT to add a instructioncontinue if err != nil?

}

// CNAMEResolve resolve CNAME if exists, and return with the highest TTL
func (hr *HostResolver) CNAMEResolve(host string) *CNAMEResolv {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method seems to be used only on this file.
WDYT to make it private?

refactor function visibility,
add error logging
fix loop control process
Copy link
Contributor

@nmengin nmengin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @gamalan .

New comments 😉

ResolvDepth int
}

// CNAMEResolv used for storing CNAME result
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please replace for storing by to store

Record string
}

// CNAMEFlatten check if CNAME records exists, flatten if possible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean records exist or record exists?

c.Assert(err, checker.IsNil)
req.Host = "frontend1.docker.local"

err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but this test only checks if the usual behavior is the same if the cnameflattening is enabled but it does not test if this one really works, it isn't?

Is it possible to add a test to check if CNAME flattening works or is it hard to check?

rules/rules.go Outdated
if types.CanonicalDomain(reqH) == types.CanonicalDomain(host) || types.CanonicalDomain(flatH) == types.CanonicalDomain(host) {
return true
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT to add a DEBUG log to indicate to user that the CNAMEFlattening did not allow resolving his domain?

Copy link
Contributor

@ldez ldez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@mmatur mmatur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@nmengin nmengin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CNAME flattening
6 participants