CLOUDSTACK-7958: Add configuration for limit to CIDRs for Admin API calls - #2046
Conversation
001eb9b to
4807373
Compare
DaanHoogland
left a comment
There was a problem hiding this comment.
this refactor seems necessary evil.
| s_logger.warn("Haproxy stickiness policy for lb rule: " + lbTO.getSrcIp() + ":" + lbTO.getSrcPort() + ": Not Applied, cause: backends are unavailable"); | ||
| } | ||
| if (publicPort.equals(NetUtils.HTTP_PORT) && !keepAliveEnabled || httpbasedStickiness) { | ||
| if (publicPort == NetUtils.HTTP_PORT && !keepAliveEnabled || httpbasedStickiness) { |
There was a problem hiding this comment.
why this? equals() seems more what is intended then ==
is making it an int really the best? as opposed to Integer (or String for that matter)
There was a problem hiding this comment.
It is a port number so it should be a Int. It's a part of the NetUtils refactor. I found that only HTTP/HTTPS port were Strings.
I wanted to make the change in other files as small as possible.
DaanHoogland
left a comment
There was a problem hiding this comment.
great change, but I think logging can improve
| public static final ConfigKey<Long> DefaultUIPageSize = new ConfigKey<Long>("Advanced", Long.class, "default.ui.page.size", "20", | ||
| "The default pagesize to be used by UI and other clients when making list* API calls", true, ConfigKey.Scope.Global); | ||
| public static final ConfigKey<String> ManagementAdminCidr = new ConfigKey<String>("Advanced", String.class, "management.admin.cidr", | ||
| "0.0.0.0/0,::/0", "Comma separated list of IPv4/IPv6 CIDRs from which Admin accounts can perform API calls", true, ConfigKey.Scope.Global); |
There was a problem hiding this comment.
argument for this default: backwards compatible
argument against: inherent security risk
There was a problem hiding this comment.
I agree. I have set it to open for all for now. We can submit a different PR afterwards to change the default imho.
| } | ||
|
|
||
| if (CallContext.current().getCallingAccount().getType() == Account.ACCOUNT_TYPE_ADMIN) { | ||
| s_logger.debug("CIDRs from which Admin accounts are allowed to perform API calls " + adminCidrs); |
There was a problem hiding this comment.
you don't want to log this on every call.
There was a problem hiding this comment.
You suggest setting this to TRACE instead of debug?
There was a problem hiding this comment.
I was thinking trace here and debug or info on the first load of the cidr
| final String serializedResponse = | ||
| apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "IP-Address of remote not in configured Admin CIDR list", | ||
| params, responseType); | ||
| HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); |
There was a problem hiding this comment.
this you do want to log on every attempt (WARN or INFO???)
There was a problem hiding this comment.
True, true. I would say WARN?
042e0d4 to
27b2f40
Compare
|
@DaanHoogland: I improved the logging as you suggested/requested. A TRACE for every request and WARN when a request is denied. Tried this locally: 2017-04-14 15:45:58,901 WARN [c.c.a.ApiServlet] (catalina-exec-17:ctx-5955fcab ctx-c572b42e) (logid:7b251506) Request by accountId 2 was denied since 192.168.122.1 does not match 127.0.0.1/8,::1/128 In this case only localhost (IPv4/IPv6) is allowed to perform requests. |
|
@PaulAngus This is what we talked about in Prague. Mind taking a look? |
|
Nice @wido, will give it a go soon! |
| final String serializedResponse = | ||
| apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "IP-Address of remote not in configured Admin CIDR list", | ||
| params, responseType); | ||
| HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); |
There was a problem hiding this comment.
@wido Great work, works fine! I'd recommend adding a return; line after the writeHttpResponse on line 304 because otherwise it will generate invalid json:
Error processing json: {"listvirtualmachinesresponse":{"uuidList":[],"errorcode":401,"errortext":"IP-Address of remote not in configured Admin CIDR list"}}{"listvirtualmachinesresponse":{}}
With return; added it works as expected:
Regards, Remi
|
Thanks @remibergsma. Added the return statement. Thinking about it. Does a 401 sound good? Or should we maybe use a 403 Forbidden? |
|
@wido I'm playing a bit with it, also because currently CloudMonkey displays a clear message but the UI will simply freeze and do nothing. Only when you look at the underlying API calls you'll see why it isn't working. I'm testing to see the http status code makes any difference of that we need to handle it in the UI somewhere. We should also think about the order: first alert on the CIDR check and then check user/pass (as it is now) or the other way around. Also noticed it doesn't work with spaces before/after comma's so we might want to add a |
|
@wido very nice feature. |
|
@remibergsma: Yes, I am aware of that UI problem. Not sure how to fix it. After thinking about it, I went for '403 Forbidden' and also stripped whitespace from the config key. I think the order is OK right now unless other opinions? @ustcweizhou: That is a lot more difficult then a global value, isn't it? Since you have to query it every time. Or should configkey allow this very easily? The CIDR list is now queried on bootstrap of ApiServlet as I didn't want to hammer the DB for every API call. |
|
@wido I think we need to do the check on two places, also on the login() method. That makes sure we don't issue a session key when user/pass are OK but we still reject it based on the CIDR. In my testing that also fixes the UI issue. There are two ways to authenticate so that makes sense I'd say. It'll then also work with authentication plugins, such as LDAP/AD. Switching the scope of the config is easy, but indeed you'll be querying it on every API call. That does have the benefit you don't need to restart the mgt server when you make a change, but the downside is also obvious. One way to resolve it, is to make a global config setting that switches the feature on/off (and that config is loaded at bootstrap) so you can opt-in for the more heavy checks. I'll play a bit more with it tonight. Update: |
|
@remibergsma: I pulled your code, thanks! It now works per account @ustcweizhou How does this look? |
| UserAccount user = null; | ||
| if (password != null && !password.isEmpty()) { | ||
| user = getUserAccount(username, password, domainId, requestParameters); | ||
| } else { |
There was a problem hiding this comment.
@wido You may want to put back this else statement. In Cosmic sso has been removed, and when I came across this left-over I removed it. However, I think it shouldn't removed from CloudStack to not break sso.
|
Good one @remibergsma. I reverted that piece and also the baremetal refusal of users. |
|
@rhtyd a Jenkins job has been kicked to build packages. I'll keep you posted as I make progress. |
|
Packaging result: ✔centos6 ✔centos7 ✔debian. JID-1505 |
|
@wido can you resolve the conflicts, thanks. |
|
I will in a few days. Can we merge this one afterwards? I keep resolving conflicts which happen since other code is merged ;) |
|
Sure, ping me @wido |
|
Ping @wido - can you fix the conflicts? |
This class had many unused methods, inconsistent names and redundant code. This commit cleans up code, renames a few methods and constants. Methods were renamed to clearly show that they are for IPv4 or IPv6. Tests were improved and added to test the changes that were made to the code. Signed-off-by: Wido den Hollander <wido@widodh.nl>
The global/account setting 'api.allowed.source.cidr.list' is set to 0.0.0.0/0,::/0 by default preserve the current behavior and thus allow API calls for accounts from all IPv4 and IPv6 subnets. Users can set it to a comma-separated list of IPv4/IPv6 subnets to restrict API calls for Admin accounts to certain parts of their network(s). This is to improve Security. Should a attacker steal the Access/Secret key of a account he/she still needs to be in a subnet from where accounts are allowed to perform API calls. This is a good security measure for APIs which are connected to the public internet. Signed-off-by: Wido den Hollander <wido@widodh.nl>
|
Done! I'll be back at work next week |
|
@blueorangutan package |
|
@rhtyd a Jenkins job has been kicked to build packages. I'll keep you posted as I make progress. |
|
Packaging result: ✔centos6 ✔centos7 ✔debian. JID-1548 |
|
@blueorangutan test |
|
@rhtyd a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests |
| Description=CloudStack Agent | ||
| Documentation=http://www.cloudstack.org/ | ||
| Requires=libvirtd.service | ||
| After=libvirtd.service |
There was a problem hiding this comment.
@wido this needs to be reverted, as the renaming of libvirtd to libvirt-bin happens via the debian packging scripts. This will cause regressions for KVM. If found KVM hosts failing to start.
|
@blueorangutan package |
|
@rhtyd a Jenkins job has been kicked to build packages. I'll keep you posted as I make progress. |
|
Packaging result: ✔centos6 ✔centos7 ✔debian. JID-1554 |
|
@blueorangutan test |
|
@rhtyd a Trillian-Jenkins test job (centos7 mgmt + kvm-centos7) has been kicked to run smoke tests |
|
Trillian test result (tid-1990)
|
|
Merging this based on 2 code reviews lgtm and test results. Checked and found the one failing smoketest to be env related. |
|
@wido sorry to bring up the old pr but how can I configure under this account level? |
….20.0.0-scclouds' Impedir o _download_ de _templates_ para _storages_ secundários que estão em `read-only` Closes #2046 See merge request scclouds/scclouds!1297


The global setting 'management.admin.cidr' is set to 0.0.0.0/0,::/0
by default preserve the current behavior and thus allow API calls
for Admin accounts from all IPv4 and IPv6 subnets.
Users can set it to a comma-separated list of IPv4/IPv6 subnets to
restrict API calls for Admin accounts to certain parts of their network(s).
This is to improve Security. Should a attacker steal the Access/Secret key
of a Admin account he/she still needs to be in a subnet from where Admin accounts
are allowed to perform API calls.
This is a good security measure for APIs which are connected to the public internet.
This PR also includes a commit to cleanup and improve NetUtils.
No existing methods have been altered. That has been verified by adding additional Unit Tests for this.