spring-cloud / spring-cloud-config

External configuration (server and client) for Spring Cloud
Apache License 2.0
1.96k stars 1.29k forks source link

provide the git username/password at run time(dynamically) #1896

Closed avnerstr closed 3 years ago

avnerstr commented 3 years ago

Hi,

From what I found so far, It seems that the only way to provide the git repo username/password can be either on the property file or as an environment variable. Both ways are unacceptable by our Infosec. For example if someone will hack and will connect to the K8s pod he can access the files or the environment variables. We need to retrieve it at runtime from vault.

Encrypt them also requires to put the secret somewhere. From the example I found so for it seems it need to be saved in the bootstrap file, so again we are in the problem of saving the secret on a file.
Is there a way I can pass the username/password dynamically at runtime?

Or if that not possible to pass the secret?

Thanks, Avner

ryanjbaxter commented 3 years ago

Is there a way I can pass the username/password dynamically at runtime? No not really.

Have you considered using SSH?

avnerstr commented 3 years ago

Correct me if I'm wrong but according to the documentation: If you do not use HTTPS and user credentials, SSH should also work out of the box when you store keys in the default directories (~/.ssh) and the URI points to an SSH location.

It means that I have a file on the filesystem with the SSH keys. It means that I still won't pass Infosec. What if someone breaks to the pod, he can get the key from the ssh default directories.

ryanjbaxter commented 3 years ago

Yes I agree if your environment is not secure than there are lots of problems that could happen from a security perspective.

The only way I can think of achieving what you are trying to do is to create your own GitCredentialsProviderFactory and set it in MultipleJGitEnvironmentRepository

https://github.com/spring-cloud/spring-cloud-config/blob/9c695648be6a88c232ed7792759fc9adfad82c2d/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java#L204

avnerstr commented 3 years ago

Thanks @ryanjbaxter

How can I set it? It means that I need to add my own configuration bean, Inject the MultipleJGitEnvironmentRepository and set it with my own GitCredentialsProviderFactory. Is that what you mean?

ryanjbaxter commented 3 years ago

Yes that is what I am thinking.

avnerstr commented 3 years ago

Thanks @ryanjbaxter. Another solution I tried and it's working is to put the password property with ENC prefix spring.cloud.config.server.git.password=ENC(eweqsacczxcz...)

and create a configuration bean that will take the secret for the encryptor at runtime.

@Bean("jasyptStringEncryptor") public StringEncryptor stringEncryptor() { PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); SimpleStringPBEConfig config = new SimpleStringPBEConfig(); config.setPassword("XXX"); // the secret I will take at runtime. config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256"); config.setKeyObtentionIterations("1000"); config.setPoolSize("1"); config.setProviderName("SunJCE"); config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator"); config.setStringOutputType("base64"); encryptor.setConfig(config); return encryptor; } But your solution, if it will work is more straight forward because it doesn't require encryption. I will update you with the results.

I have another question, regarding issue: https://github.com/spring-cloud/spring-cloud-config/issues/1899 you closed it, but I still don't understand if there is a solution for that problem? it's not clear from: https://github.com/spring-cloud/spring-cloud-config/issues/1796 to me it seems like a major security issue of the solution, so I don't understand why it's closed.

ryanjbaxter commented 3 years ago

I will comment on that issue

avnerstr commented 3 years ago

@ryanjbaxter I tried your suggestion and it doesn't work

this is my Configuration:

` @Configuration public class CodeCommitConfiguration {

MultipleJGitEnvironmentRepository multipleJGitEnvironmentRepository;
AwsCodeCommitCredentialsProviderFactory awsCodeCommitCredentialsProviderFactory;

@Autowired
public CodeCommitConfiguration(MultipleJGitEnvironmentRepository multipleJGitEnvironmentRepository,
                               AwsCodeCommitCredentialsProviderFactory awsCodeCommitCredentialsProviderFactory) {
   this.multipleJGitEnvironmentRepository = multipleJGitEnvironmentRepository;
    this.awsCodeCommitCredentialsProviderFactory = awsCodeCommitCredentialsProviderFactory;

}

@Bean
public MultipleJGitEnvironmentRepository multipleJGitEnvironmentRepository(){
    multipleJGitEnvironmentRepository.setGitCredentialsProviderFactory(awsCodeCommitCredentialsProviderFactory);
    return multipleJGitEnvironmentRepository;
}

} `

this is my own GitCredentialsProviderFactory: ` @Component public class AwsCodeCommitCredentialsProviderFactory extends GitCredentialsProviderFactory {

@Override
public CredentialsProvider createFor(String uri, String username, String password, String passphrase, boolean skipSslValidation) {
    String awsCodeCommitUserName = "...";
    String awsCodeCommitPassword = "...";
    return super.createFor(uri, awsCodeCommitUserName, awsCodeCommitPassword, passphrase, skipSslValidation);
}

} `

and I get this exception: Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'multipleJGitEnvironmentRepository': Requested bean is currently in creation: Is there an unresolvable circular reference? at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:355) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:227) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)

I also try to add - dependson("defaultEnvironmentRepository") but the same error

Any idea?

ryanjbaxter commented 3 years ago

Can you try extending MultipleJGitEnvironmentRepository and create a bean that returns that class?

avnerstr commented 3 years ago

Hi @ryanjbaxter

this code did the trick: `@Configuration public class CodeCommitConfiguration {

private AwsCodeCommitCredentialsProviderFactory awsCodeCommitCredentialsProviderFactory;
private MultipleJGitEnvironmentProperties environmentProperties;
private ConfigurableEnvironment environment;

@Autowired
public CodeCommitConfiguration(AwsCodeCommitCredentialsProviderFactory awsCodeCommitCredentialsProviderFactory,
                               MultipleJGitEnvironmentProperties environmentProperties,
                               ConfigurableEnvironment environment) {
    this.awsCodeCommitCredentialsProviderFactory = awsCodeCommitCredentialsProviderFactory;
    this.environmentProperties = environmentProperties;
    this.environment = environment;
}

@Bean
public MultipleJGitEnvironmentRepository multipleJGitEnvironmentRepository(){
    MultipleJGitEnvironmentRepository multipleJGitEnvironmentRepository = new MultipleJGitEnvironmentRepository(environment,environmentProperties);
    multipleJGitEnvironmentRepository.setGitCredentialsProviderFactory(awsCodeCommitCredentialsProviderFactory);
    return multipleJGitEnvironmentRepository;
}

} `

What I don't like about it -that in the original code, the MultipleJGitEnvironmentRepositoryFactory creates the MultipleJGitEnvironmentRepository in the build method:

`@Override public MultipleJGitEnvironmentRepository build(MultipleJGitEnvironmentProperties environmentProperties) throws Exception { if (this.connectionFactory.isPresent()) { HttpTransport.setConnectionFactory(this.connectionFactory.get()); this.connectionFactory.get().addConfiguration(environmentProperties); }

    MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment,
            environmentProperties);
    repository.setTransportConfigCallback(transportConfigCallbackFactory.build(environmentProperties));
    if (this.server.getDefaultLabel() != null) {
        repository.setDefaultLabel(this.server.getDefaultLabel());
    }
    return repository;
}`

It means that I have to copy the logic that is done in the build method to my code, what makes it problematic to maintain, in case there will be changes in the factory build, my code wont include them. Do you have an idea how to solve it?

ryanjbaxter commented 3 years ago

I agree, I think GitCredentialsProviderFactory should be a bean, and perhaps we should create an interface out of it.

ryanjbaxter commented 3 years ago

If you are interesting in contributing some code to do that, we would welcome it. If not we will try to get to it as soon as we can.

avnerstr commented 3 years ago

@ryanjbaxter, yes I would love doing that, Since I never had the chance to contribute to open source yet (lack of time) you have to guide me how to proceed.

ryanjbaxter commented 3 years ago

Sure!

Our projects work pretty similar to most GitHub projects.

Basically you fork the repo, make your changes on a branch in your fork and then submit a pull request back to our repo.

https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork

We have contribution guidelines here https://github.com/spring-cloud/spring-cloud-config#contributing

avnerstr commented 3 years ago

@ryanjbaxter it seems that when I shifted to work with the composite structure your suggested solution stopped working Any idea? ` @Override public MultipleJGitEnvironmentRepository build(MultipleJGitEnvironmentProperties environmentProperties) throws Exception { if (this.connectionFactory.isPresent()) { HttpTransport.setConnectionFactory(this.connectionFactory.get()); this.connectionFactory.get().addConfiguration(environmentProperties); }

    MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment,
            environmentProperties);
    repository.setTransportConfigCallback(transportConfigCallbackFactory.build(environmentProperties));
    if (this.server.getDefaultLabel() != null) {
        repository.setDefaultLabel(this.server.getDefaultLabel());
    }
    return repository;
}

`

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'multipleJGitEnvironmentRepository' defined in class path resource [com/imperva/microservice/application/configurations/CodeCommitConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: You need to configure a uri for the git repository. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1598) at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1562) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1451) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1338) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ... 173 common frames omitted Caused by: java.lang.IllegalStateException: You need to configure a uri for the git repository. at org.springframework.util.Assert.state(Assert.java:76) at org.springframework.cloud.config.server.environment.JGitEnvironmentRepository.afterPropertiesSet(JGitEnvironmentRepository.java:252) at org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository.afterPropertiesSet(MultipleJGitEnvironmentRepository.java:66) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ... 187 common frames omitted