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

[TH2-5132] behaviour.permittedToRemoveNamespace option #92

Merged
merged 18 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion API.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ Response body is empty, with `204 No Content` response code.
##
##
### Secrets API

`/secrets/**` are accessible for users with admin role only.
Please look at the README for `http` configuration to configure admin users.

__GET/secrets/{schema}__

__Returns:__
Expand All @@ -219,6 +223,12 @@ Set containing names of keys of custom secrets in specified schema.

__Response body example:__

__CURL example:__

`curl -u "admin:password" 'http://my-cluster:30000/editor/backend/secrets/my-schema'`

`["cassandraPassword"]`

If there are two keys in custom secrets file of this schema
```json
[
Expand Down Expand Up @@ -254,6 +264,12 @@ __Response body example:__
"key2"
]
```

__CURL example:__

`curl curl -X PUT 'http://my-cluster:30000/editor/backend/secrets/my-schema'
-u "admin:password" -H 'Content-Type: application/json'
-d '[{"key":"key1","data":"dXBkYXRlZHZhbHVl","key":"key2","data":"c29tZS1zZWNyZXQtdmFsdWU="}]'`
##
__DELETE/secrets/{schema}__

Expand All @@ -275,4 +291,24 @@ __Response body example:__
"key1"
]
```
##

##
##
### Namespace API

`/namespace/**` endpoints are accessible for users with admin role only.
Please look at the README for `http` configuration to configure admin users.

__DELETE/namespace/{schema}__

Deletes Kubernetes namespace related to `schema` if related git branch is deleted or spec.k8s-propagation: deny

__Returns:__

Name of deleted Kubernetes namespace.

__Response body example:__
`th2-my-schema`

__CURL example:__
`curl -X DELETE 'http://my-cluster:30000/editor/backend/namespace/my-schema' -u "admin:password" `
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# infra-mgr
# infra-mgr (2.4.0)
infra-mgr is a component responsible for rolling out schemas from git repository to kubernetes.
It watches for changes in the repositories and deploys changed components to kubernets.
Depending on the schema configuration, it also monitors kubernetes and if it detects external manipulation on deployed component, redeploys them from latest repository version.
Expand Down Expand Up @@ -89,8 +89,35 @@ infra-mgr configuration is given with *config.yml* file that should be on the cl
rabbitmqManagement: rabbitmq-mng-params
# individual ConfigMaps for components to be copied from infra-mgr namespace to schema namespace
# this ConfigMaps will be populated with schema specific data before copying to target namespace

behaviour:
permittedToRemoveNamespace: true
# Has infra-mgr got permission to remove Kubernetes namespace when
# branch is disabled (spec.k8s-propagation: deny) or removed.
# Infra-manager removes Kubernetes namespace when this option is true otherwise
# stops maintenance for the namespace without deleting any resources.
# Maintenance is continued when user enable or create the branch related to namespace: `<prefix><branch name>`
# Default value is `true`

http:
adminAccounts:
jack: $2a$10$OvtVdHUf1/n1YL8lrf.69e3mCLA0HLWjUusHmSSxC6dVcEfIvJM6a
emily: $2a$10$Sj2H49Lav.3BsAoq660KAeoFPQFoat8DXlpuhTtID/jJUixzZDRB6
# Map of username to encrypted by BCrypt (strength >= 10) password pairs.
# @see <a href="https://en.wikipedia.org/wiki/Bcrypt">BCrypt</a>
# This is required parameters because user must have admin role to
# access the `/secrets/**` and `/namespace/**` endpoints.
# example: `curl -u "<admin name>:<password>" 'http://localhost:8080/secrets/demo'`
```
##
## For API documentation please refer to
[API Documentation](API.md)
[API Documentation](API.md)

## Changes:

### 2.4.0
+ Added `behaviour.permittedToRemoveNamespace` option
+ Added `http.adminAccounts` required option
+ `/secrets/**` and `/namespace/**` are accessible for users with admin role only
+ `curl -X PUT 'http://localhost:8080/secrets/demo' -u "<admin name>:<password>" ...` endpoint
check secret value format when user uploads secrets via HTTP API
16 changes: 5 additions & 11 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ repositories {
mavenCentral()
}

configurations.all {
configurations.configureEach {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
exclude group: 'org.springframework.boot', module: 'logback-classic'
}
Expand Down Expand Up @@ -70,6 +70,8 @@ configurations.configureEach() {

dependencies {
implementation platform("org.springframework.boot:spring-boot-dependencies:${springboot_version}")
implementation "org.springframework.boot:spring-boot-starter-security:${springboot_version}"
implementation "org.springframework.boot:spring-boot-starter-web:${springboot_version}"

implementation "com.exactpro.th2:infra-repo:${infra_repo_version}"

Expand Down Expand Up @@ -125,16 +127,8 @@ test {
useJUnitPlatform()
}

compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
}

compileTestKotlin {
kotlinOptions {
jvmTarget = "17"
}
kotlin {
jvmToolchain(17)
}

jar {
Expand Down
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2020-2022 Exactpro (Exactpro Systems Limited)
# Copyright 2020-2023 Exactpro (Exactpro Systems Limited)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -14,9 +14,9 @@
# limitations under the License.
#

release_version = 2.3.7
release_version = 2.4.0

springboot_version = 3.1.0
kotlin_version = 1.8.22
detekt_version = 1.22.0
owaspVersion = 8.1.2
owaspVersion = 8.1.2
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2023 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.exactpro.th2.inframgr;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import java.util.List;
import java.util.Map;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class BasicAuthConfiguration {

private static final String ADMIN_ROLE = "ADMIN";

@Autowired
private Config config;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authorizeHttpRequests) ->
authorizeHttpRequests
.requestMatchers("/secrets/**").hasRole(ADMIN_ROLE)
.requestMatchers("/namespace/**").hasRole(ADMIN_ROLE)
.requestMatchers("/**").permitAll()
).httpBasic(withDefaults())
// CSRF is disabled because user uses curl only to call REST API
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}

@Bean
public UserDetailsService userDetailsService() {
Map<String, String> adminAccounts = config.getHttp().getAdminAccounts();
if (adminAccounts.isEmpty()) {
throw new IllegalStateException("'http.adminAccounts' mustn't be empty");
}

List<UserDetails> admins = adminAccounts.entrySet().stream()
.map(entry -> User.builder()
.username(entry.getKey())
.password(entry.getValue())
.roles(ADMIN_ROLE)
.build())
.toList();
return new InMemoryUserDetailsManager(admins);
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Loading
Loading