首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring Vault客户端-无法连接到本地开发Vault服务器

Spring Vault客户端-无法连接到本地开发Vault服务器
EN

Stack Overflow用户
提问于 2019-03-12 22:16:57
回答 2查看 4K关注 0票数 2

我在本地安装了Vault。基于这个官方教程https://learn.hashicorp.com/vault/,我能够启动本地开发服务器,并将一些秘密写入/读取到Vault kv中

然后,我想创建一些非常基本的Java/Spring Boot演示客户端,它将连接到我本地的Vault开发服务器,以便写入/读取机密。我阅读了Baeldung tutorial for inspiration https://www.baeldung.com/spring-vault

这是我的vault-config.properties:

vault.uri=http://127.0.0.1:8200

vault.token=s.EXg6MQwUuB63Z7Xra4zybOut (服务器最后一次启动后生成的token)

然后是服务类别:

代码语言:javascript
复制
@Service
public class CredentialsService {

    @Autowired
    private VaultTemplate vaultTemplate;

    public void secureCredentials(Credentials credentials) throws URISyntaxException {
        vaultTemplate.write("credentials/myapp", credentials);
    }

    public Credentials accessCredentials() throws URISyntaxException {
        VaultResponseSupport<Credentials> response = vaultTemplate.read("credentials/myapp", Credentials.class);
        return response.getData();
    }
}

配置类:

代码语言:javascript
复制
@Configuration
public class VaultConfig extends AbstractVaultConfiguration {

    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication("s.EXg6MQwUuB63Z7Xra4zybOut");
    }

    @Override
    public VaultEndpoint vaultEndpoint() {
        return VaultEndpoint.create("host", 8200);
    }
}

还有这个:

代码语言:javascript
复制
@Configuration
@PropertySource(value = { "vault-config.properties" })
@Import(value = EnvironmentVaultConfiguration.class)
public class VaultEnvironmentConfig {

}

一个域对象:

代码语言:javascript
复制
public class Credentials {

    private String username;
    private String password;

    public Credentials() {

    }
    public Credentials(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    @Override
    public String toString() {
        return "Credential [username=" + username + ", password=" + password + "]";
    }
}

最后是我的Spring Boot主类:

代码语言:javascript
复制
@RestController
@ComponentScan
@SpringBootApplication
public class SpringVaultTutorial {

    @Autowired
    CredentialsService credentialsService;

    @RequestMapping("/")
    String home() throws URISyntaxException {
        Credentials credentials = new Credentials("oliver","exxeta123");
        credentialsService.secureCredentials(credentials);
        return credentialsService.accessCredentials().getUsername().toString();
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringVaultTutorial.class, args);
    }

}

主类应该写入secret,然后立即读取它并打印用户名。但是我收到了这个错误消息:

出现意外错误(type=Internal服务器错误,status=500)。POST请求“https://host:8200/v1/credentials/myapp”时出现I/O错误: host;嵌套异常为java.net.UnknownHostException: host

有没有人知道哪里会出问题?

编辑:基于Arun的建议,我遵循了本教程https://drissamri.be/blog/java/enable-https-in-spring-boot/

我一直在尝试这两种方法。1)修改application.properties:

代码语言:javascript
复制
server.port: 8443
server.ssl.key-store: keystore.p12
server.ssl.key-store-password: oliver
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat
security.require-ssl=true

修改后,当我调用https://localhost:8443时,我得到了异常: javax.net.ssl.SSLException:无法识别的SSL消息,明文连接?在sun.security.ssl.InputRecord.handleUnknownRecord(InputRecord.java:710) ~na:1.8.0_121 at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973) ~na:1.8.0_121 at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) ~na:1.8.0_121 at sun.security.ssl.SSLSocketImpl在sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973) ~na:1.8.0_121sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) ~na:1.8.0_121的.startHandshake(SSLSocketImpl.java:1403) ~na:1.8.0_121

2)基于教程的第二种方法是关于添加ConnectorConfig类:

代码语言:javascript
复制
@Configuration
public class ConnectorConfig {

    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat =
                new TomcatServletWebServerFactory() {
                    @Override
                    protected void postProcessContext(Context context) {
                        SecurityConstraint securityConstraint = new SecurityConstraint();
                        securityConstraint.setUserConstraint("CONFIDENTIAL");
                        SecurityCollection collection = new SecurityCollection();
                        collection.addPattern("/*");
                        securityConstraint.addCollection(collection);
                        context.addConstraint(securityConstraint);
                    }
                };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }

    private Connector redirectConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8090);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }
}

但是在调用将我重定向到https://localhost:8443的localhost:8090后,我得到了相同的错误: javax.net.ssl.SSLException:无法识别的SSL消息,明文连接?在sun.security.ssl.InputRecord.handleUnknownRecord(InputRecord.java:710) ~

现在的问题是:我是否还需要在Vault端配置一些关于证书的内容?或者您认为Java客户端上可能存在一些证书问题?但我想如果有Java证书问题,在启动时就已经抛出异常了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-03-20 21:37:56

问题解决了。现在,我可以从Java客户端连接到本地Vault。如果将来有人想要运行simple Java Client - Vault演示,我会在这里粘贴代码。

控制器:

代码语言:javascript
复制
@RestController
@RequestMapping(Paths.ROOT)
@Api(value = Paths.ROOT, description = "Endpoint for core testing")
public class Controller {

    @Autowired
    CredentialsService credentialsService;

    @GetMapping("/")
    String home() throws URISyntaxException {
        Credentials credentials = new Credentials("oliver", "exxeta123");
        credentialsService.secureCredentials(credentials);
        return credentialsService.accessCredentials().toString();
    }

    @GetMapping("/test")
    public String test() throws IOException {
        // http://127.0.0.1:8200/v1/sys/internal/ui/mounts/secret/mysecrets
        VaultConfig vc = new VaultConfig();
        String bearerToken = vc.clientAuthentication().login().getToken();
        System.out.println(bearerToken);
        // credentialsService.accessCredentials()

        // Sending get request
        //URL url = new URL("http://127.0.0.1:8200/v1/sys/internal/ui/mounts/secret/mysecrets");
        // URL updated to match readme.adoc
        URL url = new URL("http://127.0.0.1:8200/v1/kv/my-secret");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setRequestProperty("Authorization", "Bearer " + bearerToken);
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestMethod("GET");

        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String output;

        StringBuffer response = new StringBuffer();
        while ((output = in.readLine()) != null) {
            response.append(output);
        }

        in.close();
        // printing result from response
        return "Response: - " + response.toString();
    }

    @GetMapping(value = { "/add/{name}/{username}/{password}" })
    public ResponseEntity<String> addKey(@PathVariable(value = "name", required = false, name = "name") String name,
            @PathVariable(value = "username", required = false, name = "username") String username,
            @PathVariable(value = "password", required = false, name = "password") String password) throws URISyntaxException {
        Credentials credentials = new Credentials(username, password);
        credentialsService.secureCredentials(name, credentials);
        return new ResponseEntity<>("Add success: " + credentialsService.accessCredentials(name).getUsername(), HttpStatus.OK);
    }

    @GetMapping(value = {"/get", "/get/{name}"})
    public ResponseEntity<Credentials> getKey(@PathVariable(value = "name", required = false, name = "name") String name) {
        return new ResponseEntity<>(credentialsService.accessCredentials(name), HttpStatus.OK);
    }

    @GetMapping(value= {"/delete", "/delete/{name}"})
    public String removeKey(@PathVariable(value = "name", required = false, name = "name") String name) {
        return "Delete success: " + credentialsService.deleteCredentials(name);
    }

}

服务:

代码语言:javascript
复制
@Service
public class CredentialsService {

    private VaultTemplate vaultTemplate;

    /**
     * To Secure Credentials
     *
     * @param credentials
     * @return VaultResponse
     * @throws URISyntaxException
     */
    public void secureCredentials(Credentials credentials) throws URISyntaxException {
        //vaultTemplate.write("credentials/myapp", credentials);
        initVaultTemplate();
        vaultTemplate.write("kv/myapp", credentials);
    }


    public void secureCredentials(String storagePlace, Credentials credentials) {
        initVaultTemplate();
        vaultTemplate.write("kv/" + storagePlace, credentials);
    }


    /**
     * To Retrieve Credentials
     *
     * @return Credentials
     * @throws URISyntaxException
     */
    public Credentials accessCredentials() throws URISyntaxException {
        //VaultResponseSupport<Credentials> response = vaultTemplate.read("credentials/myapp", Credentials.class);
        initVaultTemplate();
        VaultResponseSupport<Credentials> response = vaultTemplate.read("kv/myapp", Credentials.class);
        return response.getData();
        // TODO special case when there are no values
    }

    /**
     * @param nameOfsecrets key name
     * @return if is presented or empty object
     */
    public Credentials accessCredentials(String nameOfsecrets) {
        initVaultTemplate();
        VaultResponseSupport<Credentials> response = vaultTemplate.read("kv/" + nameOfsecrets, Credentials.class);
        if (response != null) {
            return response.getData();
        } else {
            return new Credentials();
        }
    }

    public boolean deleteCredentials(String name) {
        initVaultTemplate();
        vaultTemplate.delete("kv/" + name);
        return true;
    }
}

private void initVaultTemplate() {
            VaultEndpoint endpoint = new VaultEndpoint();
            endpoint.setHost("localhost");
            endpoint.setPort(8200);
            endpoint.setScheme("http");

            vaultTemplate = new VaultTemplate(endpoint, new VaultConfig().clientAuthentication());
        }

VaultConfig:

代码语言:javascript
复制
@Configuration
public class VaultConfig extends AbstractVaultConfiguration {

    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication("00000000-0000-0000-0000-000000000000");
    }

    @Override
    public VaultEndpoint vaultEndpoint() {
        return VaultEndpoint.create("localhost", 8200);
    }

}

VaultEnvironmentConfig:

代码语言:javascript
复制
@Configuration
@PropertySource(value = { "vault-config.properties" })
@Import(value = EnvironmentVaultConfiguration.class)
public class VaultEnvironmentConfig {

}

主类:

代码语言:javascript
复制
@SpringBootApplication
@EnableSwagger2
public class SpringVaultTutorial {

    public static void main(String[] args) {
        SpringApplication.run(SpringVaultTutorial.class, args);
    }

    //SWAGGER DOCUMENTATION BEANS
    // default group contains all endpoints
    @Bean
    public Docket defaultApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())//all
                .build().apiInfo(apiInfo());
    }

    // Management group contains Spring Actuator endpoints
    @Bean
    public Docket swaggerAdminEndpoints() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName(Paths.ROOT)
                .apiInfo(apiInfo())
                .select()
                .paths(PathSelectors.regex("/v1/.*"))
                .build()
                .forCodeGeneration(true);
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Vault Demo Application")
                .description("Demo Application using vault")
                .version("1.0")
                .build();
    }

}

vault-config.properties:

vault.uri=http://127.0.0.1:8200 vault.token=00000000-0000-0000-0000-000000000000

application.properties:

代码语言:javascript
复制
    server.port=8443
    server.ssl.key-alias=selfsigned_localhost_sslserver
    server.ssl.key-password=changeit
    server.ssl.key-store=classpath:ssl-server.jks
    server.ssl.key-store-provider=SUN
    server.ssl.key-store-type=JKS

路径:

代码语言:javascript
复制
public class Paths {
    public static final String ROOT = "/v1";
}

凭据:

代码语言:javascript
复制
public class Credentials {

    private String username;
    private String password;

    public Credentials() {

    }

    public Credentials(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    @Override
    public String toString() {
        return "Credential [username=" + username + ", password=" + password + "]";
    }

}
票数 2
EN

Stack Overflow用户

发布于 2019-03-12 23:52:06

UnknownHostException是由于没有名为'host‘的服务器可用。您可以在主机文件映射到localhost中添加一个条目。或尝试在创建vault时更改主机名

代码语言:javascript
复制
    @Override
    public VaultEndpoint vaultEndpoint() {
        return VaultEndpoint.create("localhost", 8200);
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55123666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档