)]}'
{"specs/keystone/2026.2/per-user-ip-allowlist.rst":[{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"f9a1f04464006a36f02e1530fcf2ede1bc36ae46","unresolved":true,"context_lines":[{"line_number":20,"context_line":"insufficient. Operators need the ability to constrain authentication to known,"},{"line_number":21,"context_line":"trusted networks on a per-user basis."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"Without this capability, operators must rely on external infrastructure (network"},{"line_number":24,"context_line":"firewalls, reverse-proxy rules, or middleware outside of Keystone) to enforce"},{"line_number":25,"context_line":"IP-based access control. These approaches are fragile, hard to audit, and"},{"line_number":26,"context_line":"disconnected from Keystone\u0027s own identity model: they cannot express rules like"}],"source_content_type":"text/x-rst","patch_set":4,"id":"5f8f40db_961bf0e6","line":23,"range":{"start_line":23,"start_character":0,"end_line":23,"end_character":80},"updated":"2026-04-20 16:00:52.000000000","message":"line too long","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":20,"context_line":"insufficient. Operators need the ability to constrain authentication to known,"},{"line_number":21,"context_line":"trusted networks on a per-user basis."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"Without this capability, operators must rely on external infrastructure (network"},{"line_number":24,"context_line":"firewalls, reverse-proxy rules, or middleware outside of Keystone) to enforce"},{"line_number":25,"context_line":"IP-based access control. These approaches are fragile, hard to audit, and"},{"line_number":26,"context_line":"disconnected from Keystone\u0027s own identity model: they cannot express rules like"}],"source_content_type":"text/x-rst","patch_set":4,"id":"bed3bc04_ad3276f7","line":23,"range":{"start_line":23,"start_character":0,"end_line":23,"end_character":80},"in_reply_to":"5f8f40db_961bf0e6","updated":"2026-04-21 05:15:11.000000000","message":"Acknowledged","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":25023,"name":"Jonathan Rosser","email":"jonathan.rosser@rd.bbc.co.uk","username":"jrosser"},"change_message_id":"671d4b429e5842bc49fdc1706ed92adda2554d4b","unresolved":true,"context_lines":[{"line_number":34,"context_line":"  obtain tokens from a known set of CIDR ranges (e.g., the management network),"},{"line_number":35,"context_line":"  reducing the blast radius if credentials are leaked."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"- As a security team, I want to enforce that privileged administrator accounts"},{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"}],"source_content_type":"text/x-rst","patch_set":4,"id":"e578b146_2995e905","line":39,"range":{"start_line":37,"start_character":0,"end_line":39,"end_character":39},"updated":"2026-04-20 20:20:25.000000000","message":"I would like to be able to restrict some auth types to only be allowed from specific ranges, i.e. \"Federated login via OIDC from anywhere, username/password only from bastion host ranges\". We had to deal with password stuffing attacks against keystone and the best answer was to just make that auth type impossible from untrusted locations.\n\nThis might be equivalent to applying a CIDR allow list to \"all users\", or allowing the rules to match a regex on the user name.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":25023,"name":"Jonathan Rosser","email":"jonathan.rosser@rd.bbc.co.uk","username":"jrosser"},"change_message_id":"effeb8a2233ba203bd5337e5fbedb80a9a1c285e","unresolved":true,"context_lines":[{"line_number":34,"context_line":"  obtain tokens from a known set of CIDR ranges (e.g., the management network),"},{"line_number":35,"context_line":"  reducing the blast radius if credentials are leaked."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"- As a security team, I want to enforce that privileged administrator accounts"},{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"}],"source_content_type":"text/x-rst","patch_set":4,"id":"837df5e6_7e4a4fbc","line":39,"range":{"start_line":37,"start_character":0,"end_line":39,"end_character":39},"in_reply_to":"15174e4c_f1fc8f67","updated":"2026-04-21 10:55:47.000000000","message":"I\u0027m not sure I understand how blocking the callback URL (I assume that this is in the context of OIDC) will have any impact on the CIDRs that are allowed to do username/password auth? Perhaps I am misunderstanding.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"bcdefee4503cf98e661d5c7dce0822c70ecd9a8a","unresolved":true,"context_lines":[{"line_number":34,"context_line":"  obtain tokens from a known set of CIDR ranges (e.g., the management network),"},{"line_number":35,"context_line":"  reducing the blast radius if credentials are leaked."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"- As a security team, I want to enforce that privileged administrator accounts"},{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"}],"source_content_type":"text/x-rst","patch_set":4,"id":"15174e4c_f1fc8f67","line":39,"range":{"start_line":37,"start_character":0,"end_line":39,"end_character":39},"in_reply_to":"50788ba1_36defdd4","updated":"2026-04-21 10:33:38.000000000","message":"I wonder if that is sufficient given opportunity to do domain mappings with federation.\nOr these should be user groups instead. Or both 😉","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"a8e305b4172b9da6280f214d13cbb78b595a9f02","unresolved":true,"context_lines":[{"line_number":34,"context_line":"  obtain tokens from a known set of CIDR ranges (e.g., the management network),"},{"line_number":35,"context_line":"  reducing the blast radius if credentials are leaked."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"- As a security team, I want to enforce that privileged administrator accounts"},{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"}],"source_content_type":"text/x-rst","patch_set":4,"id":"a7259bd4_adc39829","line":39,"range":{"start_line":37,"start_character":0,"end_line":39,"end_character":39},"in_reply_to":"837df5e6_7e4a4fbc","updated":"2026-04-21 11:18:37.000000000","message":"Yeah sorry it has nothing to do with this implementation or keystone itself. It\u0027s about how we deal with it today with L7 outside of keystone.\n\nBack to topic, would adding domain cidr allowlist support solve your use case?","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"b734fe27d7c14dc9ed6089e187637b39d4316675","unresolved":false,"context_lines":[{"line_number":34,"context_line":"  obtain tokens from a known set of CIDR ranges (e.g., the management network),"},{"line_number":35,"context_line":"  reducing the blast radius if credentials are leaked."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"- As a security team, I want to enforce that privileged administrator accounts"},{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"}],"source_content_type":"text/x-rst","patch_set":4,"id":"0d150700_e6dcbed3","line":39,"range":{"start_line":37,"start_character":0,"end_line":39,"end_character":39},"in_reply_to":"a7259bd4_adc39829","updated":"2026-04-24 13:54:09.000000000","message":"Updated spec to add support for domains and projects.\n\nthe TLDR; of the flow would be:\nAs I\u0027m also adding domain and project allowlist, there will actually be two difference types of rejections.\n\nIf it\u0027s user or user domain that is not allowed, it\u0027s an authentication error.\nIf it\u0027s the domain or project scope, it\u0027s an authorization error.\n\nSo checks would be like this:\n\nFor unscoped token:\nCheck against user allowlist -\u003e authentication failure\nCheck against user domain allowlist -\u003e authentication failure\n\nFor domain scoped token:\nCheck against user allowlist -\u003e authentication failure ﻿ ﻿\nCheck against user domain allowlist -\u003e authentication failure\nCheck against scoped domain allowlist -\u003e authorization failure\n\nFor project scoped token:\nCheck against user allowlist -\u003e authentication failure\nCheck against user domain allowlist -\u003e authentication failure\nCheck against scoped project allowlist -\u003e authorization failure\nCheck against project domain allowlist -\u003e authorization failure","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":true,"context_lines":[{"line_number":34,"context_line":"  obtain tokens from a known set of CIDR ranges (e.g., the management network),"},{"line_number":35,"context_line":"  reducing the blast radius if credentials are leaked."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"- As a security team, I want to enforce that privileged administrator accounts"},{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"}],"source_content_type":"text/x-rst","patch_set":4,"id":"50788ba1_36defdd4","line":39,"range":{"start_line":37,"start_character":0,"end_line":39,"end_character":39},"in_reply_to":"e578b146_2995e905","updated":"2026-04-21 05:15:11.000000000","message":"Today we solve it \"one layer up\" in our installations, with blocking access to the callback url during auth flow.\n\nI do see the value of something like this in keystone itself. \nMy immediate thought however would not be to use regexp on username, etc. as that becomes too loosely coupled IMO. To me it would fit better as a setting on a domain level in that case, as identity providers by default is connected to a domain.\nI.e. for users map API to `/users/{user_id}/cidrs` and domains to `/domains/{domain_id}/cidrs` for controlling cidrs.\n\nWhen issuing token, we crosscheck if the request originates from an allowed CIDR range at domain level or at user level. If any of them are met, request is allowed.\nWould that solve your use case?","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":25023,"name":"Jonathan Rosser","email":"jonathan.rosser@rd.bbc.co.uk","username":"jrosser"},"change_message_id":"671d4b429e5842bc49fdc1706ed92adda2554d4b","unresolved":true,"context_lines":[{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"},{"line_number":43,"context_line":"  than requiring firewall change requests."},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"- As an auditor, I want to be able to query the identity service directly to"},{"line_number":46,"context_line":"  determine which network restrictions are in place for a given user, without"}],"source_content_type":"text/x-rst","patch_set":4,"id":"43ebb155_90dad7f2","line":43,"range":{"start_line":41,"start_character":0,"end_line":43,"end_character":42},"updated":"2026-04-20 20:20:25.000000000","message":"If your users are federated, then you may never explicitly provision them into keystone so there is a chicken/egg situation about when you are able to apply this type of rule, i.e only if the user has already logged in, and only if there is a suitable local representation of the federated user created in the keystone db.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"},{"line_number":43,"context_line":"  than requiring firewall change requests."},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"- As an auditor, I want to be able to query the identity service directly to"},{"line_number":46,"context_line":"  determine which network restrictions are in place for a given user, without"}],"source_content_type":"text/x-rst","patch_set":4,"id":"a6ed9db7_75d92283","line":43,"range":{"start_line":41,"start_character":0,"end_line":43,"end_character":42},"in_reply_to":"43ebb155_90dad7f2","updated":"2026-04-21 05:15:11.000000000","message":"See comment above","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":25023,"name":"Jonathan Rosser","email":"jonathan.rosser@rd.bbc.co.uk","username":"jrosser"},"change_message_id":"effeb8a2233ba203bd5337e5fbedb80a9a1c285e","unresolved":false,"context_lines":[{"line_number":38,"context_line":"  can only authenticate from the corporate VPN or bastion host ranges, as"},{"line_number":39,"context_line":"  required by our compliance framework."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"- As an operator, I want a self-service API so that allowlist entries can be"},{"line_number":42,"context_line":"  managed programmatically (e.g., as part of provisioning automation) rather"},{"line_number":43,"context_line":"  than requiring firewall change requests."},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"- As an auditor, I want to be able to query the identity service directly to"},{"line_number":46,"context_line":"  determine which network restrictions are in place for a given user, without"}],"source_content_type":"text/x-rst","patch_set":4,"id":"786b3fc8_86d64426","line":43,"range":{"start_line":41,"start_character":0,"end_line":43,"end_character":42},"in_reply_to":"a6ed9db7_75d92283","updated":"2026-04-21 10:55:47.000000000","message":"It could make sense to attach to the domain for global CIDR rules, but I would still need to be able to control that per authentication method/type.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":50,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"Introduce a new, optional ``OS-IP-ALLOWLIST`` extension to Keystone that"},{"line_number":53,"context_line":"provides per-user CIDR-based IP address allowlisting. The feature is disabled"},{"line_number":54,"context_line":"by default and must be explicitly enabled through configuration."},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"When enabled, the token issuance flow is extended with an additional check: if"},{"line_number":57,"context_line":"the target user has one or more CIDR entries in their allowlist, the source IP"}],"source_content_type":"text/x-rst","patch_set":4,"id":"5f70e9a7_de7f0d24","line":54,"range":{"start_line":53,"start_character":54,"end_line":54,"end_character":64},"updated":"2026-04-20 16:20:52.000000000","message":"I don\u0027t think we need that. Would make more sense to allow * for 0.0.0.0/0 and add that to the bootstrap script:\nhttps://opendev.org/openstack/keystone/src/branch/master/keystone/cmd/bootstrap.py\n\nThis would also resolve chicken-egg during deployments, when you don\u0027t want to reconfigure keystone as a second step after configuring api.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":50,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"Introduce a new, optional ``OS-IP-ALLOWLIST`` extension to Keystone that"},{"line_number":53,"context_line":"provides per-user CIDR-based IP address allowlisting. The feature is disabled"},{"line_number":54,"context_line":"by default and must be explicitly enabled through configuration."},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"When enabled, the token issuance flow is extended with an additional check: if"},{"line_number":57,"context_line":"the target user has one or more CIDR entries in their allowlist, the source IP"}],"source_content_type":"text/x-rst","patch_set":4,"id":"91fb105e_6a757051","line":54,"range":{"start_line":53,"start_character":54,"end_line":54,"end_character":64},"in_reply_to":"5f70e9a7_de7f0d24","updated":"2026-04-21 05:15:11.000000000","message":"The chicken \u0026 egg problem is resolved as empty list is handled as allow all.\nThe reason why I suggest having it disabled is because I don\u0027t know what backends are used (I plan on shipping sql backend only)","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":80,"context_line":"- **Database migration**: A new ``ip_allowlist_entry`` table to persist the"},{"line_number":81,"context_line":"  allowlist entries."},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"- **Configuration options**: A new ``[ip_allowlist]`` configuration group"},{"line_number":84,"context_line":"  with ``enabled`` (boolean, default ``False``) and ``driver`` (string,"},{"line_number":85,"context_line":"  default ``sql``) options."},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"- **Policy rules**: RBAC enforcement ensuring only administrators can create"}],"source_content_type":"text/x-rst","patch_set":4,"id":"ee544a39_6512ed9c","line":84,"range":{"start_line":83,"start_character":54,"end_line":84,"end_character":47},"updated":"2026-04-20 16:20:52.000000000","message":"I am not sure this is needed...","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":80,"context_line":"- **Database migration**: A new ``ip_allowlist_entry`` table to persist the"},{"line_number":81,"context_line":"  allowlist entries."},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"- **Configuration options**: A new ``[ip_allowlist]`` configuration group"},{"line_number":84,"context_line":"  with ``enabled`` (boolean, default ``False``) and ``driver`` (string,"},{"line_number":85,"context_line":"  default ``sql``) options."},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"- **Policy rules**: RBAC enforcement ensuring only administrators can create"}],"source_content_type":"text/x-rst","patch_set":4,"id":"0d84a495_d5573e42","line":84,"range":{"start_line":83,"start_character":54,"end_line":84,"end_character":47},"in_reply_to":"ee544a39_6512ed9c","updated":"2026-04-21 05:15:11.000000000","message":"See comment above","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":151,"context_line":"A new extension ``OS-IP-ALLOWLIST`` v1.0 is registered. All endpoints require"},{"line_number":152,"context_line":"authentication and are subject to RBAC policy enforcement."},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"**List CIDR entries**"},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"``GET /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs``"},{"line_number":157,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"924f0274_e76f1e3f","line":154,"range":{"start_line":154,"start_character":0,"end_line":154,"end_character":21},"updated":"2026-04-20 16:20:52.000000000","message":"```suggestion\nList CIDR entries\n^^^^^^^^^^^^^^^^^\n```","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":151,"context_line":"A new extension ``OS-IP-ALLOWLIST`` v1.0 is registered. All endpoints require"},{"line_number":152,"context_line":"authentication and are subject to RBAC policy enforcement."},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"**List CIDR entries**"},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"``GET /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs``"},{"line_number":157,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"3cdc5fa8_5b5f09cb","line":154,"range":{"start_line":154,"start_character":0,"end_line":154,"end_character":21},"in_reply_to":"924f0274_e76f1e3f","updated":"2026-04-21 05:15:11.000000000","message":"Fix applied.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":177,"context_line":"        }"},{"line_number":178,"context_line":"    }"},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"**Create a CIDR entry**"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"``POST /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs``"},{"line_number":183,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"2ef19e5d_5bd62cae","line":180,"range":{"start_line":180,"start_character":0,"end_line":180,"end_character":23},"updated":"2026-04-20 16:20:52.000000000","message":"```suggestion\nCreate a CIDR entry\n^^^^^^^^^^^^^^^^^^^\n```","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":177,"context_line":"        }"},{"line_number":178,"context_line":"    }"},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"**Create a CIDR entry**"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"``POST /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs``"},{"line_number":183,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"aa1016d7_7d3984ea","line":180,"range":{"start_line":180,"start_character":0,"end_line":180,"end_character":23},"in_reply_to":"2ef19e5d_5bd62cae","updated":"2026-04-21 05:15:11.000000000","message":"Fix applied.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":195,"context_line":""},{"line_number":196,"context_line":"- Response: ``201 Created``"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"**Get a CIDR entry**"},{"line_number":199,"context_line":""},{"line_number":200,"context_line":"``GET /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs/{entry_id}``"},{"line_number":201,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"c2546897_42cb8632","line":198,"range":{"start_line":198,"start_character":0,"end_line":198,"end_character":20},"updated":"2026-04-20 16:20:52.000000000","message":"```suggestion\nGet a CIDR entry\n^^^^^^^^^^^^^^^^\n```","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":195,"context_line":""},{"line_number":196,"context_line":"- Response: ``201 Created``"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"**Get a CIDR entry**"},{"line_number":199,"context_line":""},{"line_number":200,"context_line":"``GET /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs/{entry_id}``"},{"line_number":201,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"443e93c6_8b8f1c64","line":198,"range":{"start_line":198,"start_character":0,"end_line":198,"end_character":20},"in_reply_to":"c2546897_42cb8632","updated":"2026-04-21 05:15:11.000000000","message":"Fix applied.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":202,"context_line":"- Policy: ``identity:get_ip_allowlist_cidr`` (admin or owner)"},{"line_number":203,"context_line":"- Response: ``200 OK``"},{"line_number":204,"context_line":""},{"line_number":205,"context_line":"**Delete a CIDR entry**"},{"line_number":206,"context_line":""},{"line_number":207,"context_line":"``DELETE /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs/{entry_id}``"},{"line_number":208,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"7d2ced26_4775f8a4","line":205,"range":{"start_line":205,"start_character":0,"end_line":205,"end_character":23},"updated":"2026-04-20 16:20:52.000000000","message":"```suggestion\nDelete a CIDR entry\n^^^^^^^^^^^^^^^^^^^\n```","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":202,"context_line":"- Policy: ``identity:get_ip_allowlist_cidr`` (admin or owner)"},{"line_number":203,"context_line":"- Response: ``200 OK``"},{"line_number":204,"context_line":""},{"line_number":205,"context_line":"**Delete a CIDR entry**"},{"line_number":206,"context_line":""},{"line_number":207,"context_line":"``DELETE /v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs/{entry_id}``"},{"line_number":208,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"2bbf49e5_b68e0895","line":205,"range":{"start_line":205,"start_character":0,"end_line":205,"end_character":23},"in_reply_to":"7d2ced26_4775f8a4","updated":"2026-04-21 05:15:11.000000000","message":"Fix applied.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":228,"context_line":"- The feature is disabled by default (``[ip_allowlist] enabled \u003d False``),"},{"line_number":229,"context_line":"  meaning it has zero impact on deployments that do not opt in."},{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- Only administrators can create or delete allowlist entries, preventing"},{"line_number":232,"context_line":"  unprivileged users from locking themselves or others out."},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"Operators should be aware that ``flask.request.remote_addr`` reflects the"}],"source_content_type":"text/x-rst","patch_set":4,"id":"f2138918_844fefaf","line":231,"range":{"start_line":231,"start_character":2,"end_line":231,"end_character":60},"updated":"2026-04-20 16:20:52.000000000","message":"It should be administrator or domain manager, which a special role designed to manage users within their domains.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"87b0a4b899a2ee4b4604a4756443e88413afef2e","unresolved":false,"context_lines":[{"line_number":228,"context_line":"- The feature is disabled by default (``[ip_allowlist] enabled \u003d False``),"},{"line_number":229,"context_line":"  meaning it has zero impact on deployments that do not opt in."},{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- Only administrators can create or delete allowlist entries, preventing"},{"line_number":232,"context_line":"  unprivileged users from locking themselves or others out."},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"Operators should be aware that ``flask.request.remote_addr`` reflects the"}],"source_content_type":"text/x-rst","patch_set":4,"id":"1586c4e0_87a7f7ec","line":231,"range":{"start_line":231,"start_character":2,"end_line":231,"end_character":60},"in_reply_to":"f2138918_844fefaf","updated":"2026-04-21 05:30:36.000000000","message":"Done","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":231,"context_line":"- Only administrators can create or delete allowlist entries, preventing"},{"line_number":232,"context_line":"  unprivileged users from locking themselves or others out."},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"Operators should be aware that ``flask.request.remote_addr`` reflects the"},{"line_number":235,"context_line":"immediate client address. In deployments behind a reverse proxy or load"},{"line_number":236,"context_line":"balancer, the proxy must be configured to set the correct client IP (e.g.,"},{"line_number":237,"context_line":"via ``X-Forwarded-For`` handling in the WSGI pipeline) for this feature to"}],"source_content_type":"text/x-rst","patch_set":4,"id":"c7e70512_2da340a6","line":234,"range":{"start_line":234,"start_character":31,"end_line":234,"end_character":60},"updated":"2026-04-20 16:20:52.000000000","message":"I would really prefer this thing to be configurable, and have a list of options to choose from.\nAs `X-Forwarded-For` will not result in `remote_addr` change from what I know.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"87b0a4b899a2ee4b4604a4756443e88413afef2e","unresolved":false,"context_lines":[{"line_number":231,"context_line":"- Only administrators can create or delete allowlist entries, preventing"},{"line_number":232,"context_line":"  unprivileged users from locking themselves or others out."},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"Operators should be aware that ``flask.request.remote_addr`` reflects the"},{"line_number":235,"context_line":"immediate client address. In deployments behind a reverse proxy or load"},{"line_number":236,"context_line":"balancer, the proxy must be configured to set the correct client IP (e.g.,"},{"line_number":237,"context_line":"via ``X-Forwarded-For`` handling in the WSGI pipeline) for this feature to"}],"source_content_type":"text/x-rst","patch_set":4,"id":"41707b74_fb11a8f0","line":234,"range":{"start_line":234,"start_character":31,"end_line":234,"end_character":60},"in_reply_to":"c7e70512_2da340a6","updated":"2026-04-21 05:30:36.000000000","message":"Done","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":244,"context_line":""},{"line_number":245,"context_line":"Other End User Impact"},{"line_number":246,"context_line":"---------------------"},{"line_number":247,"context_line":""},{"line_number":248,"context_line":"End users with no allowlist entries configured will see no change in"},{"line_number":249,"context_line":"behaviour regardless of whether the feature is enabled."},{"line_number":250,"context_line":""},{"line_number":251,"context_line":"Users with CIDR entries in their allowlist will receive a ``401 Unauthorized``"},{"line_number":252,"context_line":"response if they attempt to obtain a token from an IP address not covered by"}],"source_content_type":"text/x-rst","patch_set":4,"id":"fe8b4e4e_dfb0b89f","line":249,"range":{"start_line":247,"start_character":0,"end_line":249,"end_character":55},"updated":"2026-04-20 16:20:52.000000000","message":"I don\u0027t think it\u0027s how reference `check_ip_allowed()` is written:\nhttps://review.opendev.org/c/openstack/keystone/+/985406/1/keystone/ip_allowlist/core.py#42\n\nAs I assume if there will be no networks, thing will fail with exception raised.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":244,"context_line":""},{"line_number":245,"context_line":"Other End User Impact"},{"line_number":246,"context_line":"---------------------"},{"line_number":247,"context_line":""},{"line_number":248,"context_line":"End users with no allowlist entries configured will see no change in"},{"line_number":249,"context_line":"behaviour regardless of whether the feature is enabled."},{"line_number":250,"context_line":""},{"line_number":251,"context_line":"Users with CIDR entries in their allowlist will receive a ``401 Unauthorized``"},{"line_number":252,"context_line":"response if they attempt to obtain a token from an IP address not covered by"}],"source_content_type":"text/x-rst","patch_set":4,"id":"0b252640_7966016e","line":249,"range":{"start_line":247,"start_character":0,"end_line":249,"end_character":55},"in_reply_to":"fe8b4e4e_dfb0b89f","updated":"2026-04-21 05:15:11.000000000","message":"Not entirely sure I know what you mean.\nIf no CIDRs exists I return here: https://review.opendev.org/c/openstack/keystone/+/985406/1/keystone/ip_allowlist/core.py#54\n... which will allow the auth to continue","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":253,"context_line":"their allowlist. The error message will indicate that the source IP is not"},{"line_number":254,"context_line":"permitted."},{"line_number":255,"context_line":""},{"line_number":256,"context_line":"The ``python-keystoneclient`` and ``python-openstackclient`` projects may"},{"line_number":257,"context_line":"add commands for managing allowlist entries in a follow-up change (e.g.,"},{"line_number":258,"context_line":"``openstack ip allowlist cidr create``)."},{"line_number":259,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"1cdf6da5_5d7b7adb","line":256,"range":{"start_line":256,"start_character":4,"end_line":256,"end_character":29},"updated":"2026-04-20 16:20:52.000000000","message":"I think this one is already deprecated, and does not need an update? But `openstacksdk` might need an update.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"87b0a4b899a2ee4b4604a4756443e88413afef2e","unresolved":false,"context_lines":[{"line_number":253,"context_line":"their allowlist. The error message will indicate that the source IP is not"},{"line_number":254,"context_line":"permitted."},{"line_number":255,"context_line":""},{"line_number":256,"context_line":"The ``python-keystoneclient`` and ``python-openstackclient`` projects may"},{"line_number":257,"context_line":"add commands for managing allowlist entries in a follow-up change (e.g.,"},{"line_number":258,"context_line":"``openstack ip allowlist cidr create``)."},{"line_number":259,"context_line":""}],"source_content_type":"text/x-rst","patch_set":4,"id":"693aa792_81ff8a2b","line":256,"range":{"start_line":256,"start_character":4,"end_line":256,"end_character":29},"in_reply_to":"1cdf6da5_5d7b7adb","updated":"2026-04-21 05:30:36.000000000","message":"Done","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":276,"context_line":"---------------------"},{"line_number":277,"context_line":""},{"line_number":278,"context_line":"- A new ``[ip_allowlist]`` configuration group is added with two options:"},{"line_number":279,"context_line":""},{"line_number":280,"context_line":"  - ``enabled``: Boolean, default ``False``. Must be set to ``True`` to"},{"line_number":281,"context_line":"    activate the feature."},{"line_number":282,"context_line":"  - ``driver``: String, default ``sql``. Entry point for the backend driver."},{"line_number":283,"context_line":""},{"line_number":284,"context_line":"- A database migration must be run (``keystone-manage db_sync``) to create"}],"source_content_type":"text/x-rst","patch_set":4,"id":"ca9e363a_bb808943","line":281,"range":{"start_line":279,"start_character":0,"end_line":281,"end_character":25},"updated":"2026-04-20 16:20:52.000000000","message":"to be discussed","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":false,"context_lines":[{"line_number":276,"context_line":"---------------------"},{"line_number":277,"context_line":""},{"line_number":278,"context_line":"- A new ``[ip_allowlist]`` configuration group is added with two options:"},{"line_number":279,"context_line":""},{"line_number":280,"context_line":"  - ``enabled``: Boolean, default ``False``. Must be set to ``True`` to"},{"line_number":281,"context_line":"    activate the feature."},{"line_number":282,"context_line":"  - ``driver``: String, default ``sql``. Entry point for the backend driver."},{"line_number":283,"context_line":""},{"line_number":284,"context_line":"- A database migration must be run (``keystone-manage db_sync``) to create"}],"source_content_type":"text/x-rst","patch_set":4,"id":"0f1a5331_b6e3af3f","line":281,"range":{"start_line":279,"start_character":0,"end_line":281,"end_character":25},"in_reply_to":"ca9e363a_bb808943","updated":"2026-04-21 05:15:11.000000000","message":"I saw your comment in the implementation PR and explained my reasoning there.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":284,"context_line":"- A database migration must be run (``keystone-manage db_sync``) to create"},{"line_number":285,"context_line":"  the ``ip_allowlist_entry`` table."},{"line_number":286,"context_line":""},{"line_number":287,"context_line":"- Deployers using reverse proxies or load balancers must ensure that the"},{"line_number":288,"context_line":"  real client IP is propagated to Keystone (e.g., via trusted"},{"line_number":289,"context_line":"  ``X-Forwarded-For`` headers)."},{"line_number":290,"context_line":""},{"line_number":291,"context_line":"Developer Impact"},{"line_number":292,"context_line":"----------------"}],"source_content_type":"text/x-rst","patch_set":4,"id":"5970f459_d74e7c31","line":289,"range":{"start_line":287,"start_character":0,"end_line":289,"end_character":31},"updated":"2026-04-20 16:20:52.000000000","message":"afaik, X-Forwarded-For and real ip are different things... But I can be missing smth. It\u0027s up to implementation to respect X-Forwarded-For when it\u0027s present and trusted, imo.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":true,"context_lines":[{"line_number":284,"context_line":"- A database migration must be run (``keystone-manage db_sync``) to create"},{"line_number":285,"context_line":"  the ``ip_allowlist_entry`` table."},{"line_number":286,"context_line":""},{"line_number":287,"context_line":"- Deployers using reverse proxies or load balancers must ensure that the"},{"line_number":288,"context_line":"  real client IP is propagated to Keystone (e.g., via trusted"},{"line_number":289,"context_line":"  ``X-Forwarded-For`` headers)."},{"line_number":290,"context_line":""},{"line_number":291,"context_line":"Developer Impact"},{"line_number":292,"context_line":"----------------"}],"source_content_type":"text/x-rst","patch_set":4,"id":"abbcd304_24018d57","line":289,"range":{"start_line":287,"start_character":0,"end_line":289,"end_character":31},"in_reply_to":"5970f459_d74e7c31","updated":"2026-04-21 05:15:11.000000000","message":"Most proxies/lb:s allow you to set and pass that down. For instance real-ip-header + set-real-ip in nginx.\n\nYes, if we want I can add that you can specify your own custom header to be used to read client IP and have remote_addr be the default.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"87b0a4b899a2ee4b4604a4756443e88413afef2e","unresolved":false,"context_lines":[{"line_number":284,"context_line":"- A database migration must be run (``keystone-manage db_sync``) to create"},{"line_number":285,"context_line":"  the ``ip_allowlist_entry`` table."},{"line_number":286,"context_line":""},{"line_number":287,"context_line":"- Deployers using reverse proxies or load balancers must ensure that the"},{"line_number":288,"context_line":"  real client IP is propagated to Keystone (e.g., via trusted"},{"line_number":289,"context_line":"  ``X-Forwarded-For`` headers)."},{"line_number":290,"context_line":""},{"line_number":291,"context_line":"Developer Impact"},{"line_number":292,"context_line":"----------------"}],"source_content_type":"text/x-rst","patch_set":4,"id":"a98fd524_c861606d","line":289,"range":{"start_line":287,"start_character":0,"end_line":289,"end_character":31},"in_reply_to":"abbcd304_24018d57","updated":"2026-04-21 05:30:36.000000000","message":"Done","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":301,"context_line":"-----------"},{"line_number":302,"context_line":""},{"line_number":303,"context_line":"Primary assignee:"},{"line_number":304,"context_line":"  TBD"},{"line_number":305,"context_line":""},{"line_number":306,"context_line":"Work Items"},{"line_number":307,"context_line":"----------"}],"source_content_type":"text/x-rst","patch_set":4,"id":"c404e76c_ded9fa9b","line":304,"range":{"start_line":304,"start_character":0,"end_line":304,"end_character":5},"updated":"2026-04-20 16:20:52.000000000","message":"we need somebody to work on it.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"87b0a4b899a2ee4b4604a4756443e88413afef2e","unresolved":false,"context_lines":[{"line_number":301,"context_line":"-----------"},{"line_number":302,"context_line":""},{"line_number":303,"context_line":"Primary assignee:"},{"line_number":304,"context_line":"  TBD"},{"line_number":305,"context_line":""},{"line_number":306,"context_line":"Work Items"},{"line_number":307,"context_line":"----------"}],"source_content_type":"text/x-rst","patch_set":4,"id":"acbcd22e_79717cfe","line":304,"range":{"start_line":304,"start_character":0,"end_line":304,"end_character":5},"in_reply_to":"aef26839_e2c52f77","updated":"2026-04-21 05:30:36.000000000","message":"Done","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"4615992e7f8f950e71219df006d60efde2472ecf","unresolved":true,"context_lines":[{"line_number":301,"context_line":"-----------"},{"line_number":302,"context_line":""},{"line_number":303,"context_line":"Primary assignee:"},{"line_number":304,"context_line":"  TBD"},{"line_number":305,"context_line":""},{"line_number":306,"context_line":"Work Items"},{"line_number":307,"context_line":"----------"}],"source_content_type":"text/x-rst","patch_set":4,"id":"aef26839_e2c52f77","line":304,"range":{"start_line":304,"start_character":0,"end_line":304,"end_character":5},"in_reply_to":"c404e76c_ded9fa9b","updated":"2026-04-21 05:15:11.000000000","message":"Yeah I can work on it. I just wasn\u0027t sure about the process for specs. If the spec should define who should actually work on it as well. I can update it and add myself there.","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":28619,"name":"Dmitriy Rabotyagov","email":"noonedeadpunk@gmail.com","username":"noonedeadpunk"},"change_message_id":"42adcfd97fa3b675683f86304ada522e9a6ecd2a","unresolved":true,"context_lines":[{"line_number":338,"context_line":"References"},{"line_number":339,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":340,"context_line":""},{"line_number":341,"context_line":"None."}],"source_content_type":"text/x-rst","patch_set":4,"id":"5e61b024_3defc075","line":341,"range":{"start_line":341,"start_character":0,"end_line":341,"end_character":5},"updated":"2026-04-20 16:20:52.000000000","message":"please add the link to the blueprint: https://blueprints.launchpad.net/keystone/+spec/keystone-ip-allowlist\n\nhaving a reference implementation linked is a plus:\nhttps://review.opendev.org/c/openstack/keystone/+/985406","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"87b0a4b899a2ee4b4604a4756443e88413afef2e","unresolved":false,"context_lines":[{"line_number":338,"context_line":"References"},{"line_number":339,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":340,"context_line":""},{"line_number":341,"context_line":"None."}],"source_content_type":"text/x-rst","patch_set":4,"id":"2517d0d9_7e1c5de9","line":341,"range":{"start_line":341,"start_character":0,"end_line":341,"end_character":5},"in_reply_to":"5e61b024_3defc075","updated":"2026-04-21 05:30:36.000000000","message":"Done","commit_id":"08b1a42bab26fa1aebc3d6d375bc88c2e03c0752"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"cd933d2dad12f25862c3c9bc96311ddd9b792934","unresolved":true,"context_lines":[{"line_number":75,"context_line":"  (``keystone.ip_allowlist.backends.base.IPAllowlistDriverBase``) with a"},{"line_number":76,"context_line":"  default SQL implementation, following Keystone\u0027s standard driver pattern."},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"- **REST API**: A new extension providing CRUD operations for per-user CIDR"},{"line_number":79,"context_line":"  entries under ``/v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs``."},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"- **Database migration**: A new ``ip_allowlist_entry`` table to persist the"},{"line_number":82,"context_line":"  allowlist entries."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"- **Configuration options**: A new ``[ip_allowlist]`` configuration group"},{"line_number":85,"context_line":"  with ``enabled`` (boolean, default ``False``) and ``driver`` (string,"}],"source_content_type":"text/x-rst","patch_set":6,"id":"83415715_339d5c19","line":82,"range":{"start_line":78,"start_character":0,"end_line":82,"end_character":20},"updated":"2026-04-21 20:00:17.000000000","message":"This is fine for small companies with small number of administrators and a static network architecture. Bigger companies with complex networks and many admins should also profit from this feature. But with this design it will be difficult to make and track changes.\n\nJust to give you an overview - in my company there are ~400 ipv4 and ~90 ipv6 blocks. Yes, we have to push them everywhere.\n\nThe CRUD of them needs to be organized better. I would like to be able to say \"this user gets access from cidr block group \u003coffice\u003e, and this guy gets access from \u003ctailscale\u003e\".","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"b734fe27d7c14dc9ed6089e187637b39d4316675","unresolved":false,"context_lines":[{"line_number":75,"context_line":"  (``keystone.ip_allowlist.backends.base.IPAllowlistDriverBase``) with a"},{"line_number":76,"context_line":"  default SQL implementation, following Keystone\u0027s standard driver pattern."},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"- **REST API**: A new extension providing CRUD operations for per-user CIDR"},{"line_number":79,"context_line":"  entries under ``/v3/OS-IP-ALLOWLIST/users/{user_id}/cidrs``."},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"- **Database migration**: A new ``ip_allowlist_entry`` table to persist the"},{"line_number":82,"context_line":"  allowlist entries."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"- **Configuration options**: A new ``[ip_allowlist]`` configuration group"},{"line_number":85,"context_line":"  with ``enabled`` (boolean, default ``False``) and ``driver`` (string,"}],"source_content_type":"text/x-rst","patch_set":6,"id":"2b17e7e1_9f104dcf","line":82,"range":{"start_line":78,"start_character":0,"end_line":82,"end_character":20},"in_reply_to":"83415715_339d5c19","updated":"2026-04-24 13:54:09.000000000","message":"I\u0027ve updated the spec to include support for per-user, per-domain and per-project. In source (user and user domain) as well as scope (project, project_domain)","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"cd933d2dad12f25862c3c9bc96311ddd9b792934","unresolved":true,"context_lines":[{"line_number":110,"context_line":"Data Model Impact"},{"line_number":111,"context_line":"-----------------"},{"line_number":112,"context_line":""},{"line_number":113,"context_line":"A new table ``ip_allowlist_entry`` is added:"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":".. list-table::"},{"line_number":116,"context_line":"   :header-rows: 1"}],"source_content_type":"text/x-rst","patch_set":6,"id":"ebb5a09e_27aa17e9","line":113,"range":{"start_line":113,"start_character":14,"end_line":113,"end_character":32},"updated":"2026-04-21 20:00:17.000000000","message":"The name here should hint at its connection to users too. Something like `user_ip_allowlist_entry`. I can easily see how this whole functionality could be improved in the future for groups or domains.","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"b734fe27d7c14dc9ed6089e187637b39d4316675","unresolved":false,"context_lines":[{"line_number":110,"context_line":"Data Model Impact"},{"line_number":111,"context_line":"-----------------"},{"line_number":112,"context_line":""},{"line_number":113,"context_line":"A new table ``ip_allowlist_entry`` is added:"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":".. list-table::"},{"line_number":116,"context_line":"   :header-rows: 1"}],"source_content_type":"text/x-rst","patch_set":6,"id":"7ea27912_76d8ca21","line":113,"range":{"start_line":113,"start_character":14,"end_line":113,"end_character":32},"in_reply_to":"ebb5a09e_27aa17e9","updated":"2026-04-24 13:54:09.000000000","message":"The new spec I just pushed adds domain and project on top of user allowlist. I decided to keep it in the same table but added a new type to distinguish between them.","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"cd933d2dad12f25862c3c9bc96311ddd9b792934","unresolved":true,"context_lines":[{"line_number":137,"context_line":"     - Yes"},{"line_number":138,"context_line":"     - Optional human-readable description."},{"line_number":139,"context_line":"   * - ``created_at``"},{"line_number":140,"context_line":"     - BigInteger"},{"line_number":141,"context_line":"     - Yes"},{"line_number":142,"context_line":"     - Timestamp of entry creation."},{"line_number":143,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"ef7ca01a_643e0975","line":140,"updated":"2026-04-21 20:00:17.000000000","message":"Other similar fields are sql.DateTime. Why was BigInteger selected here?","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"b734fe27d7c14dc9ed6089e187637b39d4316675","unresolved":false,"context_lines":[{"line_number":137,"context_line":"     - Yes"},{"line_number":138,"context_line":"     - Optional human-readable description."},{"line_number":139,"context_line":"   * - ``created_at``"},{"line_number":140,"context_line":"     - BigInteger"},{"line_number":141,"context_line":"     - Yes"},{"line_number":142,"context_line":"     - Timestamp of entry creation."},{"line_number":143,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"b1df6614_b135166f","line":140,"in_reply_to":"ef7ca01a_643e0975","updated":"2026-04-24 13:54:09.000000000","message":"Done","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"cd933d2dad12f25862c3c9bc96311ddd9b792934","unresolved":true,"context_lines":[{"line_number":138,"context_line":"     - Optional human-readable description."},{"line_number":139,"context_line":"   * - ``created_at``"},{"line_number":140,"context_line":"     - BigInteger"},{"line_number":141,"context_line":"     - Yes"},{"line_number":142,"context_line":"     - Timestamp of entry creation."},{"line_number":143,"context_line":""},{"line_number":144,"context_line":"A unique constraint on ``(user_id, cidr)`` prevents duplicate entries."}],"source_content_type":"text/x-rst","patch_set":6,"id":"096568d9_980bd26d","line":141,"range":{"start_line":141,"start_character":7,"end_line":141,"end_character":10},"updated":"2026-04-21 20:00:17.000000000","message":"why is it nullable?","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"b734fe27d7c14dc9ed6089e187637b39d4316675","unresolved":false,"context_lines":[{"line_number":138,"context_line":"     - Optional human-readable description."},{"line_number":139,"context_line":"   * - ``created_at``"},{"line_number":140,"context_line":"     - BigInteger"},{"line_number":141,"context_line":"     - Yes"},{"line_number":142,"context_line":"     - Timestamp of entry creation."},{"line_number":143,"context_line":""},{"line_number":144,"context_line":"A unique constraint on ``(user_id, cidr)`` prevents duplicate entries."}],"source_content_type":"text/x-rst","patch_set":6,"id":"4a42f515_928182e2","line":141,"range":{"start_line":141,"start_character":7,"end_line":141,"end_character":10},"in_reply_to":"096568d9_980bd26d","updated":"2026-04-24 13:54:09.000000000","message":"Fixed. Thanks","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"cd933d2dad12f25862c3c9bc96311ddd9b792934","unresolved":true,"context_lines":[{"line_number":247,"context_line":"Notifications Impact"},{"line_number":248,"context_line":"--------------------"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"None."},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"Other End User Impact"},{"line_number":253,"context_line":"---------------------"}],"source_content_type":"text/x-rst","patch_set":6,"id":"985341eb_ca561249","line":250,"updated":"2026-04-21 20:00:17.000000000","message":"There should be. A change in anything that affects user\u0027s ability to authenticate should be noted.","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"b734fe27d7c14dc9ed6089e187637b39d4316675","unresolved":false,"context_lines":[{"line_number":247,"context_line":"Notifications Impact"},{"line_number":248,"context_line":"--------------------"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"None."},{"line_number":251,"context_line":""},{"line_number":252,"context_line":"Other End User Impact"},{"line_number":253,"context_line":"---------------------"}],"source_content_type":"text/x-rst","patch_set":6,"id":"0e7e8dce_1e627dc1","line":250,"in_reply_to":"985341eb_ca561249","updated":"2026-04-24 13:54:09.000000000","message":"Updated","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":13478,"name":"Boris Bobrov","email":"b.bobrov@sap.com","username":"bbobrov"},"change_message_id":"cd933d2dad12f25862c3c9bc96311ddd9b792934","unresolved":true,"context_lines":[{"line_number":263,"context_line":"The ``python-openstackclient`` and ``openstacksdk`` projects may"},{"line_number":264,"context_line":"add commands for managing allowlist entries in a follow-up change (e.g.,"},{"line_number":265,"context_line":"``openstack ip allowlist cidr create``)."},{"line_number":266,"context_line":""},{"line_number":267,"context_line":"Performance Impact"},{"line_number":268,"context_line":"------------------"},{"line_number":269,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"9daed9aa_78e0c82a","line":266,"updated":"2026-04-21 20:00:17.000000000","message":"does it count as an unsuccessful attempt in context of failed_auth_count and failed_auth_at?","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"},{"author":{"_account_id":26892,"name":"Marcus Murwall","email":"marcus.murwall@cleura.com","username":"muran"},"change_message_id":"b734fe27d7c14dc9ed6089e187637b39d4316675","unresolved":false,"context_lines":[{"line_number":263,"context_line":"The ``python-openstackclient`` and ``openstacksdk`` projects may"},{"line_number":264,"context_line":"add commands for managing allowlist entries in a follow-up change (e.g.,"},{"line_number":265,"context_line":"``openstack ip allowlist cidr create``)."},{"line_number":266,"context_line":""},{"line_number":267,"context_line":"Performance Impact"},{"line_number":268,"context_line":"------------------"},{"line_number":269,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"4223a791_28ea5f79","line":266,"in_reply_to":"9daed9aa_78e0c82a","updated":"2026-04-24 13:54:09.000000000","message":"It does not. I\u0027ve updated the spec to explain the reasoning behind it.","commit_id":"ff10a59a262893460d042f35ed1467c7d6e20c04"}]}
