This message was deleted.
# general
s
This message was deleted.
b
Yes. There is an
isSecret
method you can use. Let me just grab the link
a
Awesome. I honestly did try searching before asking, I promise.
b
https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/pulumi/#isSecret for nodejs... I think it's something like
.isSecretAsync()
for .net
a
Thanks!
b
btw for .net it is static on
Output.IsSecretAsync(...)
🌟 1
a
@bored-oyster-3147 @brave-planet-10645 Ok, I'm struggling a bit. Since I'm pulling this out of the config as a JsonElement all my values are JsonElements/strings.
Copy code
JsonElement data = config.RequireObject<JsonElement>("Settings");
Looping through the JsonElements I want, if I Console.WriteLine, it knows its a secret and outputs accordingly.
Copy code
Console.WriteLine(JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true }));

{
        "Region": "us-east-1",
        "SecretKey": "[secret]",
        "User": "service-worker"
}
But I'm struggling to use the Output.IsSecretAsync passing in a string or JsonElement. I tried creating a new Pulumi.Output.Create with the value, but still returns False.
Copy code
var val = Pulumi.Output.Create(item.Value);
                var isSecret = Task.Run(async () => await Output.IsSecretAsync(val));
                var isSecret2 = await Output.IsSecretAsync(val);                
                Console.WriteLine($"IsSecret: {isSecret.Result}");
                Console.WriteLine($"IsSecret: {isSecret2}");
I'm noobing something up here but I've gone cross eyed.
b
oh my bad I goofed. I don't know if
Output.IsSecretAsync
is correct for this because this is coming from config so isn't an output?
a
Correct
b
Don't you need to know if it's a secret ahead of time? Like it's the difference between using
config.RequireObject<T>
and
config.RequireSecretObject<T>
?
a
I'm pulling in a whole constructed config chunk as:
config.RequireObject<JsonElement>("Settings");
Looping over the tree
Copy code
config:
  Application:Settings:
    AppSettings:
      AllowedLoginAttempts: 4
      CaptchaInfo:
        CaptchaKey: FAKEKEY
        CaptchaSecret:
          secure: REMOVED
These are just getting piped into the parameter store for use by the application that Pulumi is spinning up
b
But when you do that I don't think pulumi is aware of anything inside that object. You're just getting the raw
JsonElement
I think. You might need to manually check if the property has the
{ "secret": { ... } }
shape inside the
JsonElement
Sorry I mean the
secure
property
a
When I loop through the tree and Console.Writeline it definitely prints everything but the secrets. It prints them as [secret]
b
yes that's because you did
RequireObject
which pulumi is not using your passphrase to deserialize so it just has the plaintext
[secret]
for those values
a
It pushes the correct value to the parameter store though, the unecrypted value of the secret
b
what is the type at the time that you pass it to the parameter store?
a
Copy code
Name = name,
 Value = item.Value.ToString()
JsonElement.Value.ToString()
b
Then I confess that at the moment I have no idea how that is functioning. I would have to do some digging
a
I piped it into an Stack Output variable too after I created it as a new Output<string> and it had the decrypted value there as well
Should I take that as you are going to do some digging? Or should I make a more formal request with support? Thanks for the help/communication thus far.
b
So I'm honestly not sure how the
JsonElement.Value.ToString()
is doing any kind of decryption but I guess that's not super relevant to your issue. To get back to your issue, it looks like internally the
Deployment
instance keeps a hash set of all of the fully qualified configuration keys that are secrets and uses this method to check that collection. It doesn't appear that this is exposed any where that I have been able to find, so maybe we could open an issue to expose something like that on the
Config
object
a
Is that something you'd like me to do?
b
I'm just a contributor 🙂 @brave-planet-10645 might have another idea but that is what I would do
a
Gotcha
b
Let me catch up with the thread
👍 1
a
Going to step out to lunch, but I'll check back
b
So JsonElement is in
System.Text.Json
so Pulumi is just converting the secret config value and passing through as
[secret]
let me ask internally here. I think we're missing something in our docs
a
Ya, because it definitely knows its a secret specifically somehow. I get the correct value as stackoutput and in AWS, and its
[secret]
like you mention if I write it out. Below is the full code I'm using to pull it out of the config, flatten the hierarchy, and write it to console. Later on I loop through the settings collection to add each key/value to AWS parameter store. Everything works perfect, other than I'd like to recognize the secrets and add them to parameter store as SecureString.
Copy code
public AppConfig()
        {
            var config = new Pulumi.Config("Application");
            JsonElement data = config.RequireObject<JsonElement>("Settings");  
            
            SettingsCollection = GetFlat(data.ToString());            

            Console.WriteLine("*************************************");
            Console.WriteLine(JsonSerializer.Serialize(SettingsCollection, new JsonSerializerOptions { WriteIndented = true }));
            Console.WriteLine("*************************************");          
        }

        public static Dictionary<string, JsonElement> GetFlat(string? json)
        {
            if (json == null) return new Dictionary<string, JsonElement>();

            IEnumerable<(string Path, JsonProperty P)> GetLeaves(string? path, JsonProperty p)
                => p.Value.ValueKind != JsonValueKind.Object
                    ? new[] { (Path: path == null ? p.Name : path + "/" + p.Name, p) }
                    : p.Value.EnumerateObject().SelectMany(child => GetLeaves(path == null ? p.Name : path + "/" + p.Name, child));

            using (JsonDocument document = JsonDocument.Parse(json)) 
                return document.RootElement.EnumerateObject()
                    .SelectMany(p => GetLeaves(null, p))
                    .ToDictionary(k => k.Path, v => v.P.Value.Clone()); //Clone so that we can use the values outside of using
        }
Example config with pulumi CLI created structured secret
Copy code
config:
  Application:Settings:
    AppSettings:
      AllowedLoginAttempts: 4
      CaptchaInfo:
        CaptchaKey: FAKEKEYasdfasdfasdf
        CaptchaSecret:
          secure: REMOVEDojiijfjio32ji23jfj0f3093j923j09
Code for the looping and ssm creation:
Copy code
foreach (var item in appConfig.SettingsCollection)
            {
                string name = $"/{prefix}/{item.Key}";
                new Ssm.Parameter(name, new Ssm.ParameterArgs
                {
                    Name = name,
                    Value = item.Value.ToString() ?? "[ERROR] config entry null",
                    Type = "String",
                    DataType = "text"
                });
            }
b
So you need to do
config.RequireSecretObject()
b
I'm still confused about how his use case is getting the decrypted values at all. I would expect it to be plaintext
[secret]
especially after seeing his
GetFlat(...)
function since he's just getting that nested
JsonElement
and doing
JsonElement.Value.ToString()
So it seems like he just needs to do
RequireSecretObject<JsonElement>()
but not so that his pulumi program functions (cause it does currently) just so that the secrets are decrypted early for the purpose of his string usage
But if he does
RequireSecretObject<JsonElement>
he still has no way of knowing which of those nested elements are actually secrets so that he can conditionally use
SecureString
in his SSM parameter resource
a
Ya, I wasn't sure how that was going to change anything either. : /
@brave-planet-10645 Did they have any insight on how the RequireSecretObject would help? Once I do the Apply in order to loop through the object I still don;'t know which individual values were secret.
b
No you won't get that information. It decrypts them all. So you have two choices here. You could either split the config model up into two and have "secret" and a "not-secret" sections, or raise an feature request here and describe what you're looking for
a
Roger.
b
Thank you